安全审计清单Skill security-checklist

这个技能提供了Web应用程序部署前的安全审计清单,覆盖认证、输入验证、秘密管理、数据库安全、网络传输、限速、日志监控和基础设施等关键领域,帮助开发人员识别和修复常见安全漏洞,确保应用程序安全上线和合规。关键词:安全审计、Web安全、部署前检查、漏洞预防、合规、OWASP、密码哈希、环境变量。

安全审计 0 次安装 0 次浏览 更新于 3/15/2026

name: security-checklist description: Web应用程序部署前的安全审计。在代码审查、现有应用程序审计或用户提到"安全审查"、“准备部署”、"上线生产"或关注漏洞时使用。覆盖认证、输入验证、秘密管理、数据库安全和合规基础。

安全清单

在交付任何Web应用程序前的最低可行安全措施。这不是详尽清单——它是防止明显灾难的基线。

部署前审计

在任何生产部署前运行此清单。如果无法勾选某项,请先修复。

认证

  • [ ] 使用bcrypt、scrypt或Argon2哈希密码(绝不用MD5/SHA1/明文)
  • [ ] 强制执行密码要求(推荐至少12个字符)
  • [ ] 会话令牌是加密随机的(使用crypto.randomBytes或等效方法)
  • [ ] 会话过期(普通应用24小时,敏感数据更短)
  • [ ] 注销时服务器端实际使会话无效
  • [ ] 密码重置令牌是单次使用并在1小时内过期
  • [ ] 失败的登录尝试被限速(5次尝试,然后冷却)
  • [ ] 代码、日志或错误消息中无凭证

输入验证

  • [ ] 所有用户输入在服务器端验证(客户端验证是用户体验,不是安全)
  • [ ] SQL查询使用参数化语句(绝不用字符串拼接)
  • [ ] HTML输出被转义以防止XSS(使用框架默认设置)
  • [ ] 文件上传验证类型、大小,并存储在Web根目录外
  • [ ] URL和重定向验证基于允许列表
  • [ ] JSON/XML解析器有实体扩展限制

秘密管理

  • [ ] 源代码或git历史中无秘密
  • [ ] 所有凭证使用环境变量或秘密管理器
  • [ ] 开发/测试/生产环境使用不同的秘密
  • [ ] API密钥具有最低所需权限
  • [ ] 秘密可以在不部署代码的情况下轮换

数据库安全

  • [ ] 数据库不暴露给公共互联网
  • [ ] 应用程序使用专用数据库用户(非root/admin)
  • [ ] 数据库用户具有最低所需权限
  • [ ] 启用行级安全(RLS)如适用
  • [ ] 备份加密并测试恢复
  • [ ] 连接字符串使用SSL/TLS

网络和传输

  • [ ] 仅使用HTTPS(重定向HTTP到HTTPS)
  • [ ] TLS 1.2+(禁用旧版本)
  • [ ] 启用HSTS头部
  • [ ] 设置安全的Cookie标志(Secure、HttpOnly、SameSite)
  • [ ] CORS为特定来源配置(生产环境中不用*

限速和DDoS

  • [ ] API端点按用户/IP限速
  • [ ] 登录端点有更严格的限制
  • [ ] 应用程序前有CDN或DDoS保护
  • [ ] 配置请求大小限制
  • [ ] 所有外部调用设置超时限制

日志记录和监控

  • [ ] 记录认证事件(登录、注销、失败尝试)
  • [ ] 日志中无敏感数据(密码、令牌、个人身份信息)
  • [ ] 日志安全存储并有保留策略
  • [ ] 配置可疑模式警报
  • [ ] 错误消息不泄露系统信息

基础设施

  • [ ] 配置防火墙(默认拒绝)
  • [ ] 关闭不必要的端口
  • [ ] SSH密钥认证(无密码认证)
  • [ ] 更新依赖(检查已知漏洞)
  • [ ] 管理界面不公开访问

按框架的常见漏洞

Node.js/Express

// 错误:SQL注入
db.query(`SELECT * FROM users WHERE id = ${req.params.id}`);

// 正确:参数化查询
db.query('SELECT * FROM users WHERE id = $1', [req.params.id]);

// 错误:XSS漏洞
res.send(`<h1>Hello ${req.query.name}</h1>`);

// 正确:使用自动转义的模板引擎
res.render('greeting', { name: req.query.name });

// 错误:代码中的秘密
const API_KEY = 'sk_live_abc123';

// 正确:环境变量
const API_KEY = process.env.API_KEY;

Python/Django/Flask

# 错误:SQL注入
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")

# 正确:参数化查询
cursor.execute("SELECT * FROM users WHERE id = %s", [user_id])

// 错误:Pickle反序列化(RCE漏洞)
data = pickle.loads(user_input)

// 正确:对不受信任数据使用JSON
data = json.loads(user_input)

// 错误:生产环境中的调试模式
app.run(debug=True)

// 正确:关闭调试,适当错误处理
app.run(debug=False)

React/前端

// 错误:通过dangerouslySetInnerHTML的XSS
<div dangerouslySetInnerHTML={{ __html: userContent }} />

// 正确:让React转义内容
<div>{userContent}</div>

// 错误:将令牌存储在localStorage(XSS可访问)
localStorage.setItem('token', authToken);

// 更好:HttpOnly Cookie(无法通过JS访问)
// 通过服务器响应头部设置

// 错误:在前端代码中暴露API密钥
const API_KEY = 'sk_live_abc123';

// 正确:通过后端代理
const response = await fetch('/api/proxy/external-service');

密码哈希参考

使用bcrypt的Node.js

const bcrypt = require('bcrypt');

// 哈希(注册时)
const saltRounds = 12;
const hashedPassword = await bcrypt.hash(plainPassword, saltRounds);

// 验证(登录时)
const isValid = await bcrypt.compare(plainPassword, hashedPassword);

使用bcrypt的Python

import bcrypt

# 哈希
hashed = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt(rounds=12))

# 验证
is_valid = bcrypt.checkpw(password.encode('utf-8'), hashed)

环境变量设置

.env文件(仅开发,永不提交)

# .env
DATABASE_URL=postgresql://user:pass@localhost:5432/myapp
JWT_SECRET=your-256-bit-secret-here
API_KEY=sk_test_xxxxx

.gitignore(必需)

.env
.env.local
.env.*.local
*.pem
*.key
credentials.json
secrets/

加载环境变量

// 使用dotenv的Node.js
require('dotenv').config();
const dbUrl = process.env.DATABASE_URL;

// 快速失败如果缺失
if (!process.env.JWT_SECRET) {
  throw new Error('JWT_SECRET环境变量必需');
}

数据库行级安全(Supabase/PostgreSQL)

-- 在表上启用RLS
ALTER TABLE documents ENABLE ROW LEVEL SECURITY;

-- 用户只能读取自己的文档
CREATE POLICY "用户可以读取自己的文档" ON documents
  FOR SELECT USING (auth.uid() = user_id);

-- 用户只能以自己的身份插入文档
CREATE POLICY "用户可以插入自己的文档" ON documents
  FOR INSERT WITH CHECK (auth.uid() = user_id);

-- 用户只能更新自己的文档
CREATE POLICY "用户可以更新自己的文档" ON documents
  FOR UPDATE USING (auth.uid() = user_id);

-- 用户只能删除自己的文档
CREATE POLICY "用户可以删除自己的文档" ON documents
  FOR DELETE USING (auth.uid() = user_id);

CORS配置

Express.js

const cors = require('cors');

// 错误:允许所有来源
app.use(cors());

// 正确:特定来源
app.use(cors({
  origin: ['https://myapp.com', 'https://www.myapp.com'],
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization'],
  credentials: true
}));

安全头部

使用Helmet的Express.js

const helmet = require('helmet');

app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'"],
      styleSrc: ["'self'", "'unsafe-inline'"],
      imgSrc: ["'self'", "data:", "https:"],
    },
  },
  hsts: {
    maxAge: 31536000,
    includeSubDomains: true,
    preload: true
  }
}));

手动头部

// 基本安全头部
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-XSS-Protection', '1; mode=block');
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
res.setHeader('Content-Security-Policy', "default-src 'self'");

不应记录的内容

// 绝不记录以下内容:
// - 密码(明文或哈希)
// - 会话令牌 / JWTs
// - API密钥
// - 信用卡号
// - 社会安全号
// - 包含用户数据的完整请求体

// 错误
console.log('登录尝试:', { email, password });
console.log('请求:', req.body);

// 正确
console.log('登录尝试:', { email, success: false, reason: 'invalid_password' });
console.log('请求:', { endpoint: req.path, method: req.method, userId: req.user?.id });

常见问题的快速修复

“我将密码存储在明文”

  1. 立即添加密码哈希
  2. 强制所有用户重置密码
  3. 使所有现有会话无效
  4. 检查数据库是否曾被暴露/泄露

“我的API密钥在git历史中”

  1. 立即轮换密钥(生成新密钥)
  2. 撤销旧密钥
  3. 使用git filter-branch或BFG Repo-Cleaner从历史中移除
  4. 强制推送(与团队协调)

“我不知道我在记录什么数据”

  1. 在代码库中搜索console.loglogger.print(
  2. 审查记录的内容
  3. 实现带有字段允许列表的结构化日志记录
  4. 设置日志轮转和保留

“我的数据库公开可访问”

  1. 立即更改数据库凭证
  2. 配置防火墙规则(仅允许应用服务器IP)
  3. 为连接启用SSL/TLS
  4. 审查访问日志以查找未授权查询

合规快速参考

您可能需要关注:

  • GDPR(欧盟用户):数据删除权、同意、违规通知
  • CCPA(加州用户):类似GDPR
  • PCI DSS(信用卡):不存储卡号,使用支付处理器
  • HIPAA(健康数据):加密、访问控制、审计日志
  • SOC 2(企业销售):安全控制文档

任何用户数据的最低要求:

  1. 隐私政策说明数据收集
  2. 用户请求数据删除的方式
  3. 传输中(HTTPS)和静态加密
  4. 访问日志和审计追踪
  5. 事件响应计划(即使是基本的)

资源