安全扫描

wescode 内置安全扫描能力,帮助你在开发阶段发现和修复安全漏洞,遵循安全编码最佳实践。

功能概览

能力说明
漏洞检测检测代码中的安全漏洞和风险
依赖审计扫描第三方依赖的已知漏洞
代码审查安全视角的代码 review
最佳实践安全编码最佳实践建议
合规检查行业安全标准合规检测

漏洞检测

自动扫描

在编码过程中,wescode 会自动检测常见的安全漏洞:

AI 实时提醒:
  ⚠ 安全风险:SQL 注入
  文件:internal/repository/user.go:45
  代码:db.Raw("SELECT * FROM users WHERE name = '" + name + "'")
  → 使用参数化查询替代字符串拼接

检测范围

漏洞类型说明严重级别
SQL 注入未参数化的 SQL 查询🔴 严重
XSS未转义的用户输入渲染🔴 严重
命令注入拼接用户输入执行系统命令🔴 严重
路径遍历未校验的文件路径访问🟠 高
硬编码凭据代码中的密钥、密码🟠 高
不安全的随机数使用 math/rand 代替 crypto/rand🟡 中
信息泄露错误信息暴露内部细节🟡 中
SSRF未校验的外部 URL 请求🟠 高
不安全的反序列化反序列化不可信数据🔴 严重
弱加密使用已知不安全的加密算法🟠 高

使用方式

用户:扫描项目的安全漏洞

AI:安全扫描结果:

  🔴 严重(2 个):

  1. SQL 注入 — internal/repository/user.go:45
     db.Raw("SELECT * FROM users WHERE email = '" + email + "'")
     修复:
     db.Raw("SELECT * FROM users WHERE email = ?", email)

  2. 硬编码 JWT 密钥 — internal/auth/jwt.go:12
     var jwtSecret = []byte("my-secret-key-123")
     修复:
     var jwtSecret = []byte(os.Getenv("JWT_SECRET"))

  🟠 高(3 个):

  3. 路径遍历 — internal/handler/file.go:28
     filepath := "/uploads/" + filename
     修复:
     filepath := filepath.Join("/uploads/", filepath.Base(filename))

  4. SSRF — internal/service/webhook.go:55
     resp, err := http.Get(userProvidedURL)
     修复:
     添加 URL 白名单校验和内网地址过滤

  5. 弱密码哈希 — internal/auth/password.go:20
     md5.Sum([]byte(password))
     修复:
     bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)

  🟡 中(4 个):
  ...

  总计:9 个安全问题
  → 是否逐个修复严重和高危问题?

依赖审计

扫描依赖漏洞

用户:检查依赖的安全性

AI:依赖安全审计报告:

  扫描范围:go.mod(45 个直接依赖 + 33 个间接依赖)

  🔴 严重漏洞(1 个):
  ┌────────────────────────────────┬──────────┬─────────┐
  │ 依赖                           │ 当前版本  │ 修复版本 │
  ├────────────────────────────────┼──────────┼─────────┤
  │ golang.org/x/crypto            │ v0.14.0  │ v0.21.0 │
  │ CVE-2024-xxxxx                 │          │         │
  │ 影响:SSH 密钥交换缓冲区溢出    │          │         │
  └────────────────────────────────┴──────────┴─────────┘

  🟠 高危漏洞(2 个):
  ┌────────────────────────────────┬──────────┬─────────┐
  │ github.com/gin-gonic/gin      │ v1.9.0   │ v1.9.1  │
  │ CVE-2024-xxxxx                 │          │         │
  │ 影响:路由参数注入              │          │         │
  ├────────────────────────────────┼──────────┼─────────┤
  │ github.com/go-sql-driver/mysql│ v1.7.0   │ v1.7.1  │
  │ CVE-2024-xxxxx                 │          │         │
  │ 影响:特殊字符转义不完整        │          │         │
  └────────────────────────────────┴──────────┴─────────┘

  ⚠ 已弃用依赖(1 个):
  - github.com/dgrijalva/jwt-go → 迁移到 github.com/golang-jwt/jwt/v5

  ✓ 安全依赖:75 个

  修复命令:
  go get golang.org/x/crypto@v0.21.0
  go get github.com/gin-gonic/gin@v1.9.1
  go get github.com/go-sql-driver/mysql@v1.7.1
  go mod tidy

定期审计

建议将依赖审计纳入 CI 流程:

# .github/workflows/security.yml
- name: 依赖安全扫描
  run: |
    go install golang.org/x/vuln/cmd/govulncheck@latest
    govulncheck ./...

代码审查

安全视角的 Review

用户:从安全角度 review 这段认证代码

AI:安全代码审查结果:

  文件:internal/auth/login.go

  ✓ 良好实践:
  - 使用 bcrypt 比较密码
  - 登录失败有速率限制
  - 密码不出现在日志中

  ⚠ 需要改进:

  1. 第 35 行:错误信息泄露
     if user == nil {
         return nil, errors.New("user not found")
     }
     if !checkPassword(password, user.PasswordHash) {
         return nil, errors.New("wrong password")
     }
     → 攻击者可以通过不同的错误信息判断用户名是否存在
     → 修复:统一返回 "invalid credentials"

  2. 第 52 行:token 过期时间过长
     token, _ := jwt.NewWithClaims(...).SignedString(secret)
     // expires in 30 days
     → 建议 access token 15 分钟,refresh token 7 天

  3. 第 60 行:未记录登录事件
     → 添加审计日志:记录 IP、User-Agent、登录结果
     → 用于异常登录检测

  4. 缺失:
     - 没有多因素认证(MFA)选项
     - 没有密码复杂度要求
     - 没有登录失败锁定机制

敏感数据检查

用户:检查代码中是否有敏感信息泄露

AI:敏感信息扫描结果:

  🔴 发现敏感信息(4 处):

  1. 硬编码 API Key
     文件:internal/service/payment.go:15
     const stripeKey = "sk_live_xxxxxxxxxxxxxxxxx"
     → 移到环境变量

  2. 测试密码泄露
     文件:internal/auth/auth_test.go:30
     password := "admin123"
     → 测试中可以接受,但确保不是生产密码

  3. 数据库连接字符串
     文件:internal/config/config.go:8
     const defaultDSN = "postgres://admin:password@localhost/db"
     → 使用环境变量,移除默认密码

  4. 私钥文件
     文件:certs/server.key
     → 添加到 .gitignore,不要提交到代码仓库

最佳实践

安全编码指南

AI 会在你编码时提供安全最佳实践建议:

输入验证

用户:如何安全地处理用户输入?

AI:输入验证最佳实践:

  1. 始终在服务端验证
     → 不要依赖前端验证

  2. 使用白名单而非黑名单
     ✗ if contains(input, "<script>") { reject }
     ✓ if !matches(input, "^[a-zA-Z0-9_]{3,32}
quot;) { reject } 3. 对不同上下文分别转义 → HTML 输出:html.EscapeString() → SQL 查询:参数化查询 → Shell 命令:不要拼接,使用 exec.Command 4. 限制输入长度和类型 → 用户名:最长 32 字符,仅字母数字 → 邮箱:标准 RFC 5322 格式 → 文件名:过滤路径分隔符 5. 使用验证库 → Go: go-playground/validator → 自定义验证器用于业务规则

认证和授权

AI:认证和授权最佳实践:

  认证:
  - 密码存储使用 bcrypt(cost >= 12)
  - JWT access token 过期时间 <= 15 分钟
  - Refresh token 单次使用后轮换
  - 支持多因素认证(TOTP)
  - 登录失败速率限制(5 次/分钟)

  授权:
  - 使用 RBAC(基于角色的访问控制)
  - 在每个端点显式检查权限
  - 不要在前端隐藏作为唯一的授权手段
  - 资源访问检查所有者身份
  - API Key 分配最小权限

加密和密钥管理

AI:加密最佳实践:

  ✓ 推荐算法:
  - 对称加密:AES-256-GCM
  - 哈希:SHA-256 / SHA-3
  - 密码哈希:bcrypt / argon2
  - 密钥交换:X25519
  - 数字签名:Ed25519

  ✗ 避免使用:
  - MD5(碰撞攻击)
  - SHA-1(碰撞攻击)
  - DES / 3DES(密钥太短)
  - RC4(多种已知攻击)

  密钥管理:
  - 不在代码中硬编码密钥
  - 使用环境变量或 Vault
  - 密钥定期轮换
  - 不同环境使用不同密钥

合规检查

OWASP Top 10 检查

用户:按 OWASP Top 10 检查项目安全

AI:OWASP Top 10 (2021) 合规检查:

  A01 - 访问控制失效
  ✓ 所有端点有认证中间件
  ⚠ 3 个端点缺少授权检查

  A02 - 加密机制失效
  ✓ HTTPS 强制
  ✗ 日志中包含未脱敏的邮箱

  A03 - 注入
  ✗ 发现 1 处 SQL 注入风险
  ✓ 其余查询使用参数化

  A04 - 不安全的设计
  ✓ 密码强度验证
  ⚠ 缺少速率限制

  A05 - 安全配置错误
  ✓ 生产环境关闭 debug
  ⚠ CORS 配置过于宽松

  A06 - 易受攻击的组件
  ✗ 2 个依赖有已知漏洞

  A07 - 认证和身份识别失效
  ✓ bcrypt 密码哈希
  ⚠ 缺少 MFA 支持

  A08 - 软件和数据完整性失效
  ✓ 依赖锁定(go.sum)

  A09 - 安全日志和监控不足
  ⚠ 缺少安全事件审计日志

  A10 - 服务端请求伪造
  ✗ 1 处 SSRF 风险

  总评:7/10 通过,3 个需要修复

数据隐私合规

用户:检查 GDPR 合规性

AI:GDPR 合规检查:

  数据收集:
  ✓ 仅收集必要的用户信息
  ⚠ 缺少隐私政策页面

  数据存储:
  ✓ 敏感数据加密存储
  ⚠ 用户数据无过期/清理策略

  数据访问:
  ⚠ 缺少用户数据导出功能
  ⚠ 缺少用户数据删除功能

  数据传输:
  ✓ 使用 HTTPS 传输
  ✓ API 通信加密

  建议:
  1. 添加 GET /api/v1/users/me/data — 数据导出
  2. 添加 DELETE /api/v1/users/me — 账号注销和数据删除
  3. 实现用户数据 30 天保留策略
  4. 添加隐私政策和 Cookie 同意

安全修复

自动修复

对于常见的安全问题,AI 可以直接生成修复代码:

用户:修复所有严重安全问题

AI:修复 2 个严重问题:

  修复 1/2:SQL 注入
  文件:internal/repository/user.go:45
  - db.Raw("SELECT * FROM users WHERE email = '" + email + "'")
  + db.Raw("SELECT * FROM users WHERE email = ?", email)

  修复 2/2:硬编码密钥
  文件:internal/auth/jwt.go:12
  - var jwtSecret = []byte("my-secret-key-123")
  + var jwtSecret = []byte(os.Getenv("JWT_SECRET"))

  ⚠ 额外步骤:
  - 确保 JWT_SECRET 环境变量已设置
  - 旧的硬编码密钥签发的 token 将失效
  - 需要通知用户重新登录

  验证:go test ./internal/... ✓ PASS

注意事项