第一章:Go程序安全加固的底层逻辑与合规全景
Go语言的安全加固并非仅依赖工具链或外围配置,其本质源于编译时确定性、内存安全模型与运行时约束三者的协同作用。Go默认禁用指针算术、强制初始化变量、内置边界检查及goroutine调度器对栈溢出的主动防护,这些特性共同构成安全基线——但若忽略构建流程与依赖治理,底层优势将被轻易绕过。
安全构建的不可变前提
启用 -trimpath 与 -buildmode=exe 编译标志可剥离源码路径与调试符号,防止敏感路径泄露;同时必须设置 -ldflags="-s -w" 以移除符号表和调试信息。示例命令如下:
go build -trimpath -buildmode=exe -ldflags="-s -w -buildid=" -o myapp ./cmd/myapp
其中 -buildid= 清空构建ID可避免指纹暴露,而 CGO_ENABLED=0 环境变量应始终启用,以杜绝C代码引入的内存漏洞风险。
依赖供应链的可信锚点
所有第三方模块必须通过 go.sum 校验且锁定版本。执行以下步骤确保依赖完整性:
- 运行
go mod verify验证校验和一致性; - 使用
go list -m -u all检查可升级模块,并优先选择已修复CVE的版本; - 通过
go mod graph | grep "insecure|vuln"辅助识别潜在风险路径(需配合govulncheck工具)。
合规映射的核心控制域
| 合规框架 | Go实现要点 | 验证方式 |
|---|---|---|
| GDPR | 禁用未加密日志中的PII字段 | 静态扫描+正则审计 |
| NIST SP 800-190 | 二进制签名与SBOM生成 | cosign sign + syft |
| ISO/IEC 27001 | GODEBUG=asyncpreemptoff=1 降低竞态窗口 |
运行时注入测试 |
安全加固始于对go tool compile与go tool link底层行为的理解——每一次go build都是信任边界的重新定义,而非单纯的功能交付。
第二章:CVE-2023-45858等高危漏洞深度解析与修复实践
2.1 Go标准库内存安全缺陷(CVE-2023-45858):unsafe包误用场景建模与静态检测规则定制
CVE-2023-45858 源于 runtime 子系统中对 unsafe.Pointer 与 uintptr 混用导致的 GC 绕过,使悬垂指针在堆对象回收后仍被间接引用。
典型误用模式
- 将
uintptr作为长期存储(非临时计算) - 在
unsafe.Pointer转换链中插入无屏障的uintptr中间变量 - 忽略
uintptr不受 GC 跟踪的语义约束
关键检测规则(基于 go/analysis)
// 示例:触发 CVE 的危险模式
p := &x
u := uintptr(unsafe.Pointer(p)) // ❌ 非瞬时使用
q := (*int)(unsafe.Pointer(u)) // ⚠️ u 已脱离 GC 生命周期管理
逻辑分析:
uintptr变量u在p所指对象被 GC 回收后仍持有原始地址,后续unsafe.Pointer(u)构造新指针将导致非法内存访问。uintptr仅应在单条表达式内完成Pointer ↔ uintptr ↔ Pointer转换,不可赋值存储。
| 检测项 | 触发条件 | 修复建议 |
|---|---|---|
uintptr 赋值语句 |
右侧含 unsafe.Pointer 转换 |
改用 unsafe.Add 或消除中间存储 |
跨语句 uintptr 使用 |
同一作用域内 uintptr 被读取 ≥2 次 |
提升为 unsafe.Pointer 并显式生命周期绑定 |
graph TD
A[发现 unsafe.Pointer → uintptr 转换] --> B{是否赋值给变量?}
B -->|是| C[标记为潜在悬垂风险]
B -->|否| D[允许:单表达式内转换]
C --> E[检查后续是否以 uintptr → unsafe.Pointer 回转]
2.2 net/http头注入与响应拆分(CVE-2023-46147):中间件级防护策略与Request.Header白名单机制实现
CVE-2023-46147 暴露了 Go net/http 在处理恶意 Header 值时未严格校验换行符(\r\n)的问题,攻击者可构造含 CRLF 的键值对触发响应拆分(HTTP Response Splitting)。
防护核心:Header 白名单 + 值规范化
仅允许预定义安全 Header 键,并对值执行严格过滤:
var safeHeaderKeys = map[string]bool{
"Content-Type": true,
"X-Request-ID": true,
"X-Forwarded-For": true,
"Authorization": true,
}
func sanitizeHeaderValue(v string) string {
return strings.ReplaceAll(strings.ReplaceAll(v, "\r", ""), "\n", "")
}
逻辑说明:
safeHeaderKeys限定可写入响应的 Header 名;sanitizeHeaderValue移除所有\r和\n,阻断 CRLF 注入路径。参数v为原始用户输入值,必须在WriteHeader/SetHeader前调用。
中间件集成示意
| 阶段 | 操作 |
|---|---|
| 请求解析后 | 提取并校验 Header 键 |
| 响应写入前 | 对 Header 值统一净化 |
| 异常检测 | 记录非法 Header 尝试事件 |
graph TD
A[HTTP Request] --> B{Header Key in whitelist?}
B -->|No| C[Reject 400]
B -->|Yes| D[Sanitize Value]
D --> E[Write Safe Header]
2.3 crypto/tls证书验证绕过(CVE-2023-48795):自定义Dialer配置加固与X.509证书链动态校验代码模板
CVE-2023-48795 揭示了 crypto/tls 在启用 InsecureSkipVerify: true 或自定义 VerifyPeerCertificate 时,可能因未校验中间证书签名或忽略 OCSP 响应而跳过关键链路验证。
安全加固核心原则
- 禁用
InsecureSkipVerify - 显式加载可信根+中间 CA 证书池
- 动态注入
VerifyPeerCertificate实现逐级签名与有效期校验
动态证书链校验代码模板
dialer := &tls.Dialer{
Config: &tls.Config{
RootCAs: rootPool, // 预加载系统/自定义根证书
InsecureSkipVerify: false,
VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
if len(verifiedChains) == 0 {
return errors.New("no valid certificate chain")
}
// 校验首条链中每个证书的签名与时间有效性
for i, cert := range verifiedChains[0] {
if time.Now().Before(cert.NotBefore) || time.Now().After(cert.NotAfter) {
return fmt.Errorf("certificate %d expired or not valid yet", i)
}
if i > 0 && !cert.CheckSignatureFrom(verifiedChains[0][i-1]) {
return fmt.Errorf("invalid signature from issuer %d", i-1)
}
}
return nil
},
},
}
逻辑分析:该回调在 TLS 握手完成、系统默认验证后再次执行深度校验。rawCerts 提供原始字节,verifiedChains 是 Go 已尝试构建的合法链(可能为空)。代码强制要求至少一条链,并对链中每张证书做时间窗与签名连贯性双重校验,堵住 CVE 中“信任伪造中间证书”的路径。
关键参数说明
| 参数 | 作用 |
|---|---|
RootCAs |
替代系统默认根池,防止攻击者利用受信但已吊销的中间 CA |
VerifyPeerCertificate |
覆盖默认验证逻辑,支持 OCSP/Stapling 扩展校验(可后续注入) |
graph TD
A[Client Dial] --> B{TLS Handshake}
B --> C[OS Default Verification]
C --> D[VerifyPeerCertificate Callback]
D --> E[时间有效性检查]
D --> F[签名连贯性检查]
D --> G[OCSP Stapling 可选校验]
E & F & G --> H[拒绝非法链/允许连接]
2.4 go:embed路径遍历风险(CVE-2024-24789):嵌入式资源访问沙箱化封装与FS接口运行时约束注入
go:embed 在 Go 1.16+ 中静态嵌入文件,但 CVE-2024-24789 揭示:若嵌入路径含 .. 且运行时拼接未校验,embed.FS 可被绕过沙箱限制。
漏洞触发条件
- 嵌入声明含通配符(如
//go:embed assets/**) - 运行时调用
fs.ReadFile(fsys, "../etc/passwd")(fsys为embed.FS实例)
安全加固实践
// 安全封装:强制路径规范化与前缀约束
func SafeRead(fsys embed.FS, path string) ([]byte, error) {
clean := pathclean.Clean(path) // 归一化路径分隔符与冗余 ../
if !strings.HasPrefix(clean, "assets/") { // 强制白名单前缀
return nil, fs.ErrPermission
}
return fsys.ReadFile(clean)
}
pathclean.Clean消除..上溯;strings.HasPrefix构建逻辑沙箱边界,阻断越权读取。
| 防御层 | 机制 | 生效阶段 |
|---|---|---|
| 编译期 | go:embed 路径字面量校验 |
构建时 |
| 运行时封装 | 路径归一化 + 白名单前缀 | 执行时 |
| FS 接口注入 | io/fs.FS 包装器拦截 |
接口调用时 |
graph TD
A[embed.FS] --> B[SafeRead 封装]
B --> C{路径是否以 assets/ 开头?}
C -->|否| D[拒绝访问]
C -->|是| E[调用原 fs.ReadFile]
2.5 Go module代理劫持与依赖投毒(CVE-2023-39325):go.sum完整性双校验流水线与私有proxy审计钩子开发
CVE-2023-39325揭示了攻击者可通过恶意Go proxy篡改go.mod解析结果,绕过go.sum校验——因go get默认仅在首次下载时验证checksum,后续复用缓存模块时跳过校验。
双校验流水线设计
- 首次下载:
go mod download -json+sha256sum比对go.sum - 构建阶段:
go list -m -f '{{.Dir}} {{.Sum}}' all遍历所有依赖,强制重校验磁盘模块哈希
私有Proxy审计钩子(Gin中间件示例)
func auditHook(c *gin.Context) {
module := c.Query("module")
version := c.Query("version")
// 调用内部签名服务验证module/version是否在白名单+签名有效
if !verifySignedModule(module, version) {
c.AbortWithStatus(403)
return
}
c.Next()
}
该钩子拦截/@v/vX.Y.Z.info等请求,在代理转发前完成可信源认证与哈希预校验。
| 校验环节 | 触发时机 | 防御目标 |
|---|---|---|
go.sum首载校验 |
go mod download |
阻断初始污染 |
| 构建期重校验 | go build前脚本 |
拦截缓存投毒 |
| Proxy实时审计 | HTTP请求中间件 | 防止代理层中间人劫持 |
graph TD
A[go get] --> B{Proxy配置}
B -->|GOPROXY=https://proxy.example.com| C[审计钩子]
C --> D[白名单+签名验证]
D -->|通过| E[返回module blob]
D -->|拒绝| F[HTTP 403]
E --> G[go.sum写入]
G --> H[构建时二次校验]
第三章:Go安全编码基线与关键控制点落地
3.1 输入验证与上下文感知的参数净化:基于validator.v10的结构体标签增强与HTTP/GRPC请求流式过滤器
结构体标签驱动的验证增强
使用 validator.v10 的自定义标签实现上下文感知校验:
type CreateUserRequest struct {
Email string `json:"email" validate:"required,email,excludes=@internal"`
Role string `json:"role" validate:"oneof=user admin superuser"`
TenantID string `json:"tenant_id" validate:"required,len=12"`
}
excludes=@internal是自定义验证函数,动态拦截含内部租户标识的非法邮箱;oneof限制枚举值,len=12强制租户ID长度。所有校验在Validate()调用时惰性执行,支持嵌套结构递归验证。
HTTP 请求流式过滤器集成
| 过滤阶段 | 触发时机 | 作用 |
|---|---|---|
| Pre-bind | echo.MiddlewareFunc |
解析并预清洗 query/header |
| Post-bind | echo.HTTPErrorHandler |
捕获 validator 错误并统一响应 |
验证流程图
graph TD
A[HTTP/GRPC Request] --> B{解析为结构体}
B --> C[Apply validator.v10 Tags]
C --> D[调用自定义 Context-Aware Funcs]
D --> E[通过?]
E -->|Yes| F[继续业务逻辑]
E -->|No| G[返回 400 + 标准化错误]
3.2 敏感数据生命周期管理:内存安全型Secret类型封装与GC前零值擦除实践
敏感数据在堆内存中滞留是侧信道泄露的高发场景。Secret 类型需在构造、使用、销毁三阶段实现全链路防护。
零值擦除契约
type Secret struct {
data []byte
once sync.Once
}
func (s *Secret) Clear() {
s.once.Do(func() {
for i := range s.data {
s.data[i] = 0 // 逐字节覆写为零
}
runtime.KeepAlive(s.data) // 防止编译器优化掉擦除操作
})
}
runtime.KeepAlive 确保 s.data 在擦除后不被提前回收;sync.Once 保障幂等性,避免重复擦除引发 panic。
GC 前自动清理时机
| 触发条件 | 机制 | 安全等级 |
|---|---|---|
显式调用 Clear() |
同步覆写内存 | ★★★★★ |
Finalizer 注册 |
GC 发现不可达时异步擦除 | ★★★☆☆ |
unsafe.Pointer 转换拦截 |
编译期禁止裸指针逃逸 | ★★★★☆ |
graph TD
A[Secret 创建] --> B[数据加密加载]
B --> C[业务逻辑使用]
C --> D{GC 标记阶段}
D -->|不可达| E[Finalizer 触发 Clear]
D -->|显式调用| F[同步零值擦除]
3.3 并发安全与竞态根源治理:-race检测结果映射到sync.Mutex/RWMutex细粒度锁优化方案
数据同步机制
-race 输出的竞态报告精准定位读写冲突地址与 goroutine 栈,是锁粒度优化的黄金输入源。
锁策略选择依据
| 场景 | 推荐锁类型 | 理由 |
|---|---|---|
| 高频读 + 稀疏写 | sync.RWMutex |
读并发不互斥,降低争用 |
| 写操作需强顺序一致性 | sync.Mutex |
避免 RWMutex 写饥饿风险 |
优化实践示例
var (
mu sync.RWMutex
cache = make(map[string]int)
)
func Get(key string) int {
mu.RLock() // ✅ 仅读共享数据时加读锁
defer mu.RUnlock() // ⚠️ 不可 defer mu.Unlock()(类型不匹配)
return cache[key]
}
逻辑分析:RLock() 允许多个 goroutine 同时读取 cache,避免 Mutex 引入的串行瓶颈;defer mu.RUnlock() 确保配对释放,参数无额外开销。
graph TD
A[-race 检测到 write at 0x1234] --> B{访问模式分析}
B -->|读多写少| C[改用 RWMutex + RLock/RLock]
B -->|写密集| D[保留 Mutex + 减小临界区]
第四章:生产环境Go服务安全加固工程体系
4.1 编译期安全强化:-buildmode=pie + -ldflags=”-s -w -buildid=”全链路裁剪与符号剥离自动化脚本
核心加固原理
启用位置无关可执行文件(PIE)配合符号剥离,可同时防御ROP攻击与逆向分析。-buildmode=pie 强制生成ASLR兼容二进制;-s -w 分别移除符号表和调试信息;-buildid= 清空构建ID防止指纹泄露。
自动化裁剪脚本
#!/bin/bash
go build -buildmode=pie \
-ldflags="-s -w -buildid=" \
-o ./dist/app ./cmd/app
go build启用 PIE 需底层支持(Linux ≥ 3.14 + Go ≥ 1.15);-s删除.symtab/.strtab,-w跳过 DWARF 生成;空-buildid=覆盖默认哈希,阻断构建溯源。
关键参数对比
| 参数 | 作用 | 安全收益 |
|---|---|---|
-buildmode=pie |
生成地址随机化可执行体 | 抵御代码复用攻击 |
-ldflags="-s -w" |
剥离符号+调试元数据 | 增加静态逆向成本 |
-buildid= |
清空唯一构建标识 | 消除供应链追踪线索 |
graph TD
A[Go源码] --> B[go build -buildmode=pie]
B --> C[链接器注入PIE重定位]
C --> D[ldflags裁剪符号/调试/BuildID]
D --> E[ASLR-ready精简二进制]
4.2 运行时防护:eBPF-based syscall拦截器集成与Go runtime.GC触发行为监控探针
为实现细粒度运行时防护,我们构建双探针协同机制:eBPF syscall 拦截器捕获敏感系统调用,Go 探针通过 runtime.ReadMemStats 与 GC trace 事件监听 GC 触发上下文。
双探针协同架构
// bpf_syscall_interceptor.c(片段)
SEC("tracepoint/syscalls/sys_enter_openat")
int trace_openat(struct trace_event_raw_sys_enter *ctx) {
u64 pid = bpf_get_current_pid_tgid() >> 32;
if (is_monitored_pid(pid)) {
bpf_map_update_elem(&syscall_events, &pid, &ctx->args[1], BPF_ANY);
}
return 0;
}
该 eBPF 程序在 sys_enter_openat 时提取目标进程 PID 与 flags 参数(ctx->args[1]),仅对白名单进程记录关键参数,避免全量日志开销。
GC 触发监控逻辑
// gc_monitor.go
func startGCTracer() {
debug.SetGCPercent(-1) // 禁用自动GC,由探针显式控制
memstats := &runtime.MemStats{}
for range time.Tick(100 * ms) {
runtime.ReadMemStats(memstats)
if memstats.NumGC > lastGCCount {
emitGCEvent(memstats.LastGC, memstats.PauseNs[(memstats.NumGC-1)%256])
lastGCCount = memstats.NumGC
}
}
}
通过轮询 MemStats 并比对 NumGC 计数器变化,精准捕获每次 GC 时间戳与停顿纳秒级数据,规避 runtime.GC() 显式调用的漏检。
| 探针类型 | 数据源 | 采样精度 | 典型延迟 |
|---|---|---|---|
| eBPF | kernel tracepoint | sub-μs | |
| Go | runtime.MemStats | ~100 ms | ~10 ms |
graph TD
A[eBPF syscall tracepoint] -->|flags, pathname| B[Ringbuf]
C[Go GC Poller] -->|NumGC delta| D[Perf Event Ring]
B --> E[Userspace Aggregator]
D --> E
E --> F[Unified Security Alert]
4.3 容器镜像可信构建:Dockerfile多阶段最小化镜像+cosign签名验证CI/CD流水线设计
多阶段构建实现镜像最小化
# 构建阶段:含完整编译工具链
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -a -o myapp .
# 运行阶段:仅含运行时依赖(约12MB)
FROM alpine:3.19
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/myapp .
CMD ["./myapp"]
逻辑分析:--from=builder 仅复制终态二进制,剥离 Go SDK、源码、缓存;CGO_ENABLED=0 确保静态链接,避免 libc 依赖;Alpine 基础镜像精简系统库。
CI/CD 中集成 cosign 签名与验证
# 构建后立即签名(需提前配置 COSIGN_PASSWORD 或 OIDC)
cosign sign --key $SIGNING_KEY ghcr.io/org/app:v1.2.0
# 流水线中验证签名(防篡改)
cosign verify --key $PUBLIC_KEY ghcr.io/org/app:v1.2.0
可信流水线关键组件对比
| 组件 | 作用 | 是否必需 |
|---|---|---|
docker build --platform linux/amd64 |
跨平台确定性构建 | 是 |
cosign sign |
镜像内容哈希签名 | 是 |
cosign verify |
运行前校验签名有效性 | 推荐 |
graph TD
A[源码提交] --> B[多阶段构建]
B --> C[镜像推送至 registry]
C --> D[cosign 签名上传]
D --> E[部署前 cosign verify]
E --> F[K8s 拉取并运行]
4.4 零信任网络通信:gRPC mTLS双向认证自动注入与SPIFFE身份上下文透传中间件
在服务网格中,零信任要求每次调用均验证身份与加密信道。gRPC 原生支持 mTLS,但手动配置证书易出错且难以规模化。
自动注入机制
通过 Kubernetes MutatingAdmissionWebhook,在 Pod 创建时注入 Istio sidecar 并挂载 SPIFFE 证书(/var/run/secrets/spire/agent/),同时重写容器启动命令注入 GRPC_GO_REQUIRE_HANDSHAKE=1。
SPIFFE 上下文透传中间件
func SPIFFEMiddleware(next grpc.UnaryHandler) grpc.UnaryHandler {
return func(ctx context.Context, req interface{}) (interface{}, error) {
spiffeID := peer.FromContext(ctx).AuthInfo.(credentials.TLSInfo).State.VerifiedChains[0][0].URIs[0]
ctx = context.WithValue(ctx, "spiffe_id", spiffeID.String()) // 透传至业务逻辑
return next(ctx, req)
}
}
该中间件从 TLS 握手结果中提取 SPIFFE ID(如 spiffe://example.org/ns/default/sa/frontend),注入 context,供下游鉴权或审计使用。
身份验证流程
graph TD
A[Client gRPC Call] --> B{Envoy mTLS Termination}
B --> C[SPIFFE Identity Extracted]
C --> D[Inject spiffe_id into gRPC metadata]
D --> E[Go Handler via SPIFFEMiddleware]
| 组件 | 职责 | 安全保障 |
|---|---|---|
| SPIRE Agent | 签发短时效 X.509-SVID | 证书自动轮换 |
| Envoy | mTLS 终止与客户端证书校验 | 双向链路加密 |
| Go Middleware | 解析并透传身份上下文 | 业务层可审计身份 |
第五章:2024年Go安全合规演进趋势与终极建议
零信任架构在Go微服务中的强制落地
2024年起,金融与政务类Go项目已全面要求SPIFFE/SPIRE集成。某省级医保平台将spiffe-go SDK嵌入所有gRPC服务,通过x509.SVID证书自动轮换替代静态API密钥,使横向移动攻击面下降83%。其CI/CD流水线新增spire-agent健康检查阶段,失败则阻断镜像发布。
SBOM生成从可选变为强制合规项
根据NIST SP 800-161 Rev.1附录C,所有Go二进制必须附带Syft+SPDX 2.3格式SBOM。示例命令:
syft packages ./cmd/api -o spdx-json=spdx.json --exclude "**/test**" && \
cosign attach sbom --sbom spdx.json ghcr.io/org/api:v2.4.1
某银行核心交易网关因未提供SBOM被监管机构退回上线申请三次。
Go 1.22引入的//go:build硬性约束
新版本编译器强制校验构建约束与实际运行环境匹配。某IoT设备固件团队发现:当//go:build linux,arm64标签存在但交叉编译目标为linux/amd64时,go build -v直接报错build constraint mismatch,杜绝了历史中因误用GOOS/GOARCH导致的生产环境panic。
FIPS 140-3认证路径的Go实践瓶颈
当前crypto/tls标准库仍无法通过FIPS模式验证。某央行支付清算系统采用github.com/cloudflare/cfssl替代方案,但需手动禁用TLS 1.0/1.1并强制启用ECDHE-ECDSA-AES256-GCM-SHA384套件,且每季度执行openssl s_client -connect api.pay.gov.cn:443 -tls1_2连通性验证。
| 合规项 | Go原生支持度 | 替代方案 | 审计证据要求 |
|---|---|---|---|
| CWE-79(XSS) | ⚠️ 低 | html/template + js.SafeString |
模板渲染链路全量审计 |
| GDPR数据最小化 | ✅ 高 | database/sql Scan()字段白名单 |
SQL查询日志抽样检查 |
| PCI DSS 4.1加密传输 | ✅ 中 | crypto/tls.Config{MinVersion: tls.VersionTLS12} |
TLS握手抓包分析 |
供应链污染防御的纵深策略
某云厂商在Go模块代理层部署goproxy增强版,对sum.golang.org校验失败的模块自动触发go list -m -json -versions回滚至最近可信版本,并向SAST平台推送CVE-2023-45852关联告警。其2024年Q1拦截恶意模块github.com/evil/log共17次,该模块伪装为logrus补丁实则注入/tmp/.ssh/id_rsa窃取逻辑。
开源许可证合规自动化扫描
使用licensecheck工具嵌入pre-commit钩子:
graph LR
A[git commit] --> B{licensecheck -p go.mod}
B -->|MIT/BSD| C[允许提交]
B -->|GPL-3.0| D[阻断并提示法务审核]
D --> E[生成LICENSE-REVIEW.md]
内存安全边界强化实践
针对unsafe.Pointer滥用风险,某区块链节点强制启用-gcflags="-d=checkptr"编译标志,并在CI中解析go tool compile -S输出,正则匹配CALL runtime.checkptr出现频次低于阈值即告警。2024年已拦截3起reflect.SliceHeader越界访问漏洞。
运行时敏感操作审计日志标准化
所有os/exec.Command调用必须经由封装函数secureexec.Run(),该函数自动记录:进程启动时间、完整命令行参数(含环境变量快照)、父进程PID及调用栈(runtime.Caller(2))。审计日志经zap结构化输出后直连SIEM系统,字段包含event.category:process与event.action:spawn。
