mcpField
G
go-security-audit

go-security-audit

github.com/eduardo-sl安全83107 次安装2 周前更新
代码仓库

关于 go-security-audit

go-security-audit 是面向 Go 开发者的安全审计技能,可用于检查代码变更或整个代码库。它结合扫描器结果与人工检查,并按严重程度整理发现。

主要功能

  1. 01支持定向、差异和全面审计
  2. 02指导运行 govulncheck、gosec 和 go vet
  3. 03检查输入处理、注入与访问控制
  4. 04审查密钥、TLS、响应头、限流和日志
  5. 05发现项包含文件行号、输入路径和修复建议

适用场景

  1. 01合并 PR 前审查 Go 代码变更
  2. 02检查 Go 服务中的常见安全隐患
  3. 03审计身份验证或输入处理路径
  4. 04整理按优先级排序的安全报告

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/eduardo-sl/go-agent-skills --skill go-security-audit

安装后在 Claude Code 中输入/go-security-audit确认已加载。

详细介绍

Go 安全审计

安全不是一项功能,而是一种属性。每一行代码要么维护安全,要么削弱安全。

工作模式

开始前,请根据请求选择匹配的模式:

  • 定向检查 — 针对单一问题(“这个查询是否存在注入风险?”、“审查此身份验证中间件”)。只应用相关章节。
  • 差异审计 — 审计 PR 或工作树中的变更行,检查下方列出的所有问题。
  • 完整审计(“对该服务进行安全审查”的默认模式)— 使用“审计大型代码库”中的并行检查流程扫描整个代码库。

先运行扫描器

手动审查前,先运行自动化扫描器,并将其输出纳入审计结果(未安装的扫描器可跳过,并注明原因):

govulncheck ./...       # known CVEs actually reachable from your code
gosec ./...             # static analysis for insecure patterns
go vet ./...            # includes some security-relevant checks

扫描器可以发现已知模式;下面的手动检查流程则用于发现它们无法检测的逻辑缺陷。

审计大型代码库

下面每个编号章节都是一次独立的审计检查。对于超过约 20 个文件的代码库:

  1. 先定位攻击面:HTTP/gRPC 处理器、CLI 入口、队列消费者,以及任何解析外部输入的代码。
  2. 针对每个问题分别检查:(a) 输入验证和注入,(b) 身份验证/授权,(c) 密钥和加密,(d) TLS、安全标头和速率限制,(e) 日志记录规范。
  3. 如果你的环境支持将工作委派给并行子 Agent 或任务,则为每项检查分配一个 Agent——这些检查彼此不重叠。否则按顺序执行。
  4. 每项发现都必须注明 file.go:line、存在漏洞的输入路径以及具体修复方案。汇总成一份按严重程度排序的报告。

1. 输入验证

绝不要信任用户输入。在边界处进行验证:
// ✅ Good — validate before use
func (h *Handler) handleCreate(w http.ResponseWriter, r *http.Request) {
    // Limit body size
    r.Body = http.MaxBytesReader(w, r.Body, 1<<20) // 1 MB

    var req CreateRequest
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
        respondError(w, http.StatusBadRequest, "invalid JSON")
        return
    }

    if err := validate.Struct(req); err != nil {
        respondError(w, http.StatusBadRequest, "validation failed")
        return
    }
    // proceed with validated data
}
字符串清理:
// Sanitize HTML to prevent XSS
import "github.com/microcosm-cc/bluemonday"

p := bluemonday.UGCPolicy()
sanitized := p.Sanitize(userInput)

// Validate email format
import "net/mail"
_, err := mail.ParseAddress(email)

// Validate URLs
u, err := url.Parse(input)
if err != nil || (u.Scheme != "http" && u.Scheme != "https") {
    // reject
}

2. SQL 注入防护

始终使用参数化查询:
// ✅ Good — parameterized
row := db.QueryRowContext(ctx,
    "SELECT id, name FROM users WHERE email = $1", email)

// ✅ Good — with sqlx named params
query := "SELECT * FROM users WHERE name = :name AND age > :age"
rows, err := db.NamedQueryContext(ctx, query, map[string]interface{}{
    "name": name,
    "age":  minAge,
})

// ❌ CRITICAL — string concatenation = SQL injection
query := "SELECT * FROM users WHERE email = '" + email + "'"
query := fmt.Sprintf("SELECT * FROM users WHERE id = %s", id)
动态查询:

构建动态 WHERE 子句时,请使用查询构建器或安全的字符串拼接:

// ✅ Good — safe dynamic query building
var conditions []string
var args []interface{}
argIdx := 1

if name != "" {
    conditions = append(conditions, fmt.Sprintf("name = $%d", argIdx))
    args = append(args, name)
    argIdx++
}

query := "SELECT * FROM users"
if len(conditions) > 0 {
    query += " WHERE " + strings.Join(conditions, " AND ")
}

3. 身份验证和授权

密码处理:
import "golang.org/x/crypto/bcrypt"

// Hash password
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)

// Verify password — constant-time comparison built in
err := bcrypt.CompareHashAndPassword(hash, []byte(password))

绝不要存储明文密码。绝不要使用 MD5/SHA 处理密码。

JWT 验证:
// ✅ Always validate:
// 1. Signature (algorithm must match expectation)
// 2. Expiration (exp claim)
// 3. Issuer (iss claim)
// 4. Audience (aud claim)

// ❌ CRITICAL — never disable signature verification
// ❌ CRITICAL — never accept "alg": "none"
// ❌ CRITICAL — never hardcode signing keys in source code
授权中间件:
func RequireRole(role string) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            user := UserFromContext(r.Context())
            if user == nil || !user.HasRole(role) {
                http.Error(w, "forbidden", http.StatusForbidden)
                return
            }
            next.ServeHTTP(w, r)
        })
    }
}

4. 密钥管理

规则:
  • 🔴 绝不要在源代码中硬编码密钥、令牌或 API 密钥
  • 🔴 绝不要将密钥提交到 git(包括“测试”文件)
  • 🔴 绝不要记录密钥、令牌或密码
// ✅ Good — from environment
dbURL := os.Getenv("DATABASE_URL")

// ✅ Good — from secrets manager
secret, err := secretsManager.GetSecret(ctx, "api-key")

// ❌ CRITICAL
const apiKey = "sk-1234567890abcdef" // hardcoded secret
使用 .gitignore:
.env
*.pem
*.key
credentials.json
扫描泄露的密钥:
# Use gitleaks in CI
gitleaks detect --source=. --verbose

5. HTTP 安全标头

func SecurityHeaders(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("X-Content-Type-Options", "nosniff")
        w.Header().Set("X-Frame-Options", "DENY")
        w.Header().Set("Content-Security-Policy", "default-src 'self'")
        w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains")
        w.Header().Set("X-XSS-Protection", "0") // modern browsers handle this
        next.ServeHTTP(w, r)
    })
}

6. TLS 配置

tlsConfig := &tls.Config{
    MinVersion: tls.VersionTLS12,
    CipherSuites: []uint16{
        tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
        tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
    },
    PreferServerCipherSuites: true,
}

srv := &http.Server{
    TLSConfig: tlsConfig,
    // ...
}

7. 速率限制

import "golang.org/x/time/rate"

type RateLimiter struct {
    limiters sync.Map
    rate     rate.Limit
    burst    int
}

func (rl *RateLimiter) Allow(key string) bool {
    limiter, _ := rl.limiters.LoadOrStore(key,
        rate.NewLimiter(rl.rate, rl.burst))
    return limiter.(*rate.Limiter).Allow()
}

对身份验证端点、公共 API 以及任何消耗大量资源的操作应用速率限制。

8. 日志安全

// ❌ CRITICAL — logging sensitive data
log.Printf("user login: email=%s password=%s", email, password)
log.Printf("auth token: %s", token)
log.Printf("request body: %v", req) // may contain secrets

// ✅ Good — redact sensitive fields
log.Printf("user login: email=%s", email)
logger.Info("auth completed", slog.String("user_id", userID))

安全审计检查清单

严重(🔴 阻断项)
  • 不存在 SQL 注入风险(所有查询均使用参数化方式)
  • 不存在硬编码的密钥/令牌
  • 不存储明文密码
  • 未禁用 TLS 证书验证
  • 已限制请求正文大小
  • 已验证 JWT 签名,并拒绝 alg: none
重要(🟡 警告)
  • 对所有外部数据进行输入验证
  • 对身份验证端点和公共端点启用速率限制
  • 对所有响应设置安全标头
  • 严格配置 CORS
  • 错误消息不会泄露内部信息
  • 对身份验证事件进行审计日志记录
建议(🟢 建议项)
  • 在 CI 流水线中使用 govulncheck
  • 使用 gitleaks 扫描密钥
  • 使用带有脱敏功能的结构化日志
  • 固定依赖版本并验证校验和

评论

支持 Markdown