安全编码守卫(Secure Code Guardian)
概述
安全编码守卫是一套将安全实践嵌入开发全流程的方法论。从威胁建模到安全验证,确保代码在设计阶段就考虑安全性,而非事后补救。核心理念:默认安全失败(Fail Secure),而非默认开放失败(Fail Open)。
五步安全工作流
- 威胁建模(Threat Model) -- 识别资产、攻击面和潜在威胁
- 安全设计(Design) -- 选择合适的安全架构和防御方案
- 安全实现(Implement) -- 按照安全编码规范编写代码
- 安全验证(Validate) -- 通过测试和审计验证安全措施有效
- 安全文档(Document) -- 记录安全决策和已知风险
OWASP Top 10 速查
| 排名 | 威胁 | 防御模式 |
|---|---|---|
| A01 | 访问控制失效(Broken Access Control) | 默认拒绝,基于角色的权限校验 |
| A02 | 加密失败(Cryptographic Failures) | 使用 TLS 1.3,AES-256-GCM 加密敏感数据 |
| A03 | 注入攻击(Injection) | 参数化查询,输入验证,输出编码 |
| A04 | 不安全设计(Insecure Design) | 威胁建模,安全设计评审 |
| A05 | 安全配置错误(Security Misconfiguration) | 最小权限原则,自动化配置检查 |
| A06 | 脆弱组件(Vulnerable Components) | 依赖扫描,及时更新 |
| A07 | 认证失败(Authentication Failures) | 多因素认证,强密码策略 |
| A08 | 数据完整性失败(Data Integrity Failures) | 签名验证,CI/CD 安全 |
| A09 | 日志监控不足(Logging Failures) | 结构化日志,异常告警 |
| A10 | SSRF(Server-Side Request Forgery) | URL 白名单,禁止内网访问 |
认证安全检查清单
- 密码哈希使用 bcrypt 或 argon2,绝不使用 MD5/SHA1
- 实施登录速率限制(Rate Limiting),防止暴力破解
- 会话管理(Session Management):设置合理的过期时间,登录后刷新会话 ID
- JWT 令牌:使用短有效期,实现刷新机制,验证签名算法
输入验证模式
// 参数化查询 -- 防止 SQL 注入
const result = await db.query(
'SELECT * FROM users WHERE id = $1', [userId]
);
// Zod Schema 验证 -- 类型安全的输入校验
const UserInput = z.object({
email: z.string().email(),
age: z.number().int().min(0).max(150),
});
// HTML 输出编码 -- 防止 XSS
const safeHtml = escapeHtml(userInput);
XSS / CSRF 防御
- 内容安全策略(CSP):配置
Content-Security-Policy头,限制脚本来源 - CSRF 令牌:每个表单携带一次性令牌,服务端验证
- 输出编码(Output Encoding):所有用户输入在渲染前必须编码
安全响应头检查清单
| 头部 | 作用 | 推荐值 |
|---|---|---|
| Strict-Transport-Security | 强制 HTTPS | max-age=31536000; includeSubDomains |
| X-Content-Type-Options | 防止 MIME 嗅探 | nosniff |
| X-Frame-Options | 防止点击劫持 | DENY 或 SAMEORIGIN |
| Content-Security-Policy | 限制资源加载来源 | 按需配置,禁止 unsafe-inline |
| Referrer-Policy | 控制 Referer 泄漏 | strict-origin-when-cross-origin |
Node.js 项目可使用 Helmet.js 一键配置上述安全头。
必须做 / 禁止做
必须做:
- 所有输入都经过验证和清洗
- 数据库查询使用参数化方式
- 密码使用 bcrypt/argon2 哈希
- 启用 HTTPS 和安全响应头
- 实施最小权限原则
- 记录安全相关事件的审计日志
- 依赖项定期扫描和更新
- 默认安全失败(Fail Secure)-- 异常时拒绝访问而非放行
禁止做:
- 禁止在代码中硬编码密钥或凭据
- 禁止使用 MD5 或 SHA1 做密码哈希
- 禁止信任客户端输入不做服务端验证
- 禁止在错误信息中暴露内部实现细节
- 禁止使用
eval()或动态代码执行 - 禁止关闭 HTTPS 或降级到 HTTP
- 禁止在日志中记录明文密码或敏感数据
- 禁止默认开放失败(Fail Open)-- 异常时放行是重大安全隐患
Fail Secure vs Fail Open
- Fail Secure(安全失败):系统出错时默认拒绝访问。例:认证服务宕机时拒绝所有请求。
- Fail Open(开放失败):系统出错时默认允许访问。绝大多数场景下这是错误选择。
- 原则:宁可拒绝合法用户,也不放过恶意请求。