OWASP Top 10 是 Web 安全的"必读清单",每 3-4 年更新一次,反映当下最严重的应用层安全问题。但很多团队对它的认识停留在"听说过",真到了开发中并没系统防护。这篇文章把 2021 版 OWASP Top 10 完整讲透,所有威胁配真实代码示例和修复方案,2024 年新趋势也会提到。
A01 Broken Access Control(失效的访问控制)
排第一,因为最普遍。本质:用户能访问不该访问的资源。
水平越权
# 错:用户能改任意 id 的资源
GET /api/orders/123 # 用户 A 拿自己的订单
GET /api/orders/124 # 改一下 URL,拿用户 B 的订单 —— 也能拿到!
# 修复:每次访问都校验"这资源属于当前用户"
def get_order(order_id):
order = db.find_order(order_id)
if order.user_id != current_user.id:
return forbidden()
return order
垂直越权
# 错:普通接口里漏了权限校验
POST /api/admin/users/delete # 后端没检查 role
# 修复:加权限装饰器
@require_role('admin')
def delete_user(...):
...
检测方法
每个接口都问:"这个接口能做什么 + 谁应该能做 + 我现在校验了什么"。漏了任何一环就是漏洞。Burp Suite、OWASP ZAP 等工具能自动化测试越权。
A02 Cryptographic Failures(加密失败)
对应旧版的"敏感数据泄露"。涉及:
- 明文存密码 / 信用卡。
- 用过时算法(MD5、SHA1、DES、RC4)。
- 密钥写在代码里。
- HTTP 传输敏感数据(不走 TLS,在 HTTP 之上加一层 TLS 加密,防止中间人窃听和篡改。">HTTPS)。
# 错:MD5 存密码
password_hash = hashlib.md5(password.encode()).hexdigest()
# MD5 已被破解,撞库工具几秒搞定
# 对:bcrypt / argon2
import bcrypt
hash = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))
# 验证
bcrypt.checkpw(password.encode(), hash)
规则:
- 密码用 bcrypt / argon2 / scrypt,不要用 SHA 系列。
- 对称加密用 AES-GCM,不要用 ECB 模式。
- 非对称用 RSA-OAEP / ECC,不要用 PKCS#1 v1.5。
- 密钥用 KMS / Vault 管理,绝不进代码仓库。
- TLS 1.2+ 强制,旧版本(SSLv3 / TLS 1.0 / 1.1)关闭。
A03 Injection(注入)
SQL 注入、NoSQL 注入、命令注入、LDAP 注入、模板注入。本质都是"用户输入被当作代码执行"。
SQL 注入
# 错:字符串拼接
sql = f"SELECT * FROM users WHERE name = '{username}'"
# username = "admin' OR '1'='1" -> 绕过认证
# username = "x'; DROP TABLE users; --" -> 直接干掉表
# 对:参数化查询
cursor.execute("SELECT * FROM users WHERE name = ?", (username,))
命令注入
# 错:用户输入拼到 shell
os.system(f"ping {host}")
# host = "google.com; rm -rf /" -> 删了
# 对:用列表传参,不走 shell
subprocess.run(["ping", "-c", "1", host], shell=False)
NoSQL 注入
# 错:MongoDB 接受用户传 JSON
db.users.find({ "username": req.body.username, "password": req.body.password });
// 攻击者传:{ "username": "admin", "password": { "$ne": null } }
// 等于查"有任何密码的 admin"
// 对:校验输入类型
if (typeof req.body.password !== 'string') return error();
A04 Insecure Design(不安全的设计)
这是 2021 新增的类别,强调"设计阶段的安全缺陷" —— 不是写错代码,而是设计本身就漏了威胁建模。
例子:密码重置只验证邮箱,没有验证旧密码或二步认证 —— 邮箱被劫持就丢账号。修复:多因素认证、Threat Modeling 在设计阶段就识别风险。
A05 Security Misconfiguration(安全配置错误)
- 用默认密码(admin/admin、root/root)。
- 错误信息泄露技术栈("Stack Trace 出现在用户页面")。
- 未禁用调试端点(
/actuator暴露在公网)。 - 权限配置过宽(S3 bucket public-read 暴露内部数据)。
- HTTP Header 缺失(没有 Content-Security-Policy、X-Frame-Options)。
# 必备 HTTP 安全头
Strict-Transport-Security: max-age=31536000; includeSubDomains
Content-Security-Policy: default-src 'self'; ...
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), microphone=()
A06 Vulnerable and Outdated Components(易受攻击和过时的组件)
用了有 CVE 的库。修复:
- 持续扫描依赖:Dependabot、Snyk、Trivy、SCA(Software Composition Analysis)工具。
- 及时升级:CVE 公开后大概几天就会出现批量扫描的攻击者。
- 固定版本:lock 文件(package-lock.json、Pipfile.lock)防止隐式升级到坏版本。
2021 年的 Log4Shell(CVE-2021-44228)是这类问题的极致案例 —— 一个 Log4j 库的远程代码执行,影响全球几百万系统,因为这个库几乎装在每个 Java 项目里。
A07 Identification and Authentication Failures(身份认证失败)
- 密码弱:允许 "123456"、不限制尝试次数。
- Session 管理差:Session ID 可预测、不绑定 IP、不过期。
- 没有多因素认证。
- 密码恢复流程脆弱:只发邮件就能重置,且不限制次数。
修复:强密码策略、限流登录尝试(5 次失败锁 15 分钟)、强制 MFA(至少给管理员账号)、Session 适当短(15-60 分钟)、登出主动清 Session。
A08 Software and Data Integrity Failures(软件和数据完整性失败)
- 反序列化漏洞:Python pickle、PHP unserialize、Java 反序列化 —— 把用户输入直接反序列化能触发任意代码执行。
- 不验证更新的完整性:CDN 加载的 JS / 第三方依赖被替换,你的应用执行恶意代码。
- CI/CD 缺乏完整性:构建脚本被改、镜像被替换。
# JS 加载第三方脚本要校验完整性(SRI)
<script src="https://cdn.example.com/lib.js"
integrity="sha384-xxx"
crossorigin="anonymous"></script>
# 浏览器会校验哈希,不匹配就拒绝执行
# 不要反序列化不可信数据
pickle.loads(user_input) # 危险!
json.loads(user_input) # 安全,只是数据
A09 Security Logging and Monitoring Failures(安全日志和监控失败)
没记日志 = 出了事查不到。需要记录:
- 登录尝试(成功 + 失败,带 IP / UA)。
- 权限变更(谁给谁授了什么权限)。
- 敏感操作(转账、删除、导出数据)。
- API 错误(尤其 401/403/500)。
同时要告警:登录失败激增 / 权限授予异常 / 错误率飙升 → 立刻通知安全团队。
A10 Server-Side Request Forgery (SSRF)
服务器收到用户输入的 URL,主动去访问 —— 如果 URL 是内网地址或云元数据接口,就泄露了内部信息。
# 错:用户输入图片 URL,服务端 download
@app.route('/download')
def download():
url = request.args.get('url')
response = requests.get(url)
return response.content
# 攻击:url = http://169.254.169.254/latest/meta-data/iam/security-credentials/
# AWS / 阿里云 / GCP 都有这个内网元数据接口,返回临时密钥!
# 修复:URL 白名单 / 禁止访问内网 / 校验响应 IP
import ipaddress
def is_safe_url(url):
host = urlparse(url).hostname
ip = socket.gethostbyname(host)
addr = ipaddress.ip_address(ip)
return not (addr.is_private or addr.is_loopback or addr.is_link_local)
SSRF 在云时代尤其危险 —— 元数据接口里的临时凭证一旦泄漏,攻击者能用它访问云资源(读 S3、改 IAM 角色、起 EC2)。所有"服务端代理用户 URL"的接口必须严格白名单。
2024 年的新威胁趋势
- AI / LLM 安全:Prompt Injection、训练数据投毒、模型泄露。OWASP 已经出了"OWASP Top 10 for LLM Applications"。
- 供应链攻击:不是攻击你的代码,而是攻击你的依赖、构建工具、CI/CD。SolarWinds、xz-utils 后门都是这类。
- API 暴露:微服务时代 API 数量爆炸,文档化 / 访问控制 / 限流跟不上。
实战:把安全做进开发流程
- SAST(静态代码扫描):SonarQube、Semgrep。每次 PR 跑。
- SCA(依赖扫描):Snyk、Dependabot。监控 CVE。
- DAST(动态扫描):OWASP ZAP、Burp Suite。预发环境定期跑。
- Threat Modeling:每个新功能设计阶段做"STRIDE"分析。
- Pentest:每年一次外部渗透测试。
- Bug Bounty:让白帽子帮你找漏洞,有偿。
XSS 跨站脚本攻击详解
XSS 不在 2021 OWASP Top 10 单独列出(归入 Injection),但仍然是 Web 最常见的攻击之一。三种类型:
1. 反射型 XSS
# 用户被诱导点击恶意链接:
https://app.com/search?q=<script>steal_cookie()</script>
# 后端把 q 直接拼进 HTML:
<p>搜索结果:</p> -> <p>搜索结果:<script>...</script></p>
# 浏览器执行了脚本
2. 存储型 XSS
用户评论里包含 <script>,被存到数据库,其他用户看评论时执行。比反射型危害大。
3. DOM 型 XSS
// 前端直接用 URL 参数渲染
document.getElementById('greet').innerHTML = location.hash.slice(1);
// hash = "#<img src=x onerror=alert(1)>" -> XSS
防御
- 输出转义:所有从用户输入来的内容,渲染到 HTML 时用
htmlspecialchars/escape。 - 禁用 innerHTML:用
textContent或框架内置(React 的 JSX 自动转义)。 - CSP:Content-Security-Policy 头限制 inline script 和外部脚本来源。
script-src 'self'强制脚本只能从自己域名加载,即使 XSS 注入也跑不起来。 - HttpOnly Cookie:登录 cookie 设 HttpOnly,XSS 偷不走。
CSRF 跨站请求伪造
用户在 A 网站登录,B 网站构造一个请求让用户提交,浏览器会带上 A 的 cookie:
# B 网站的页面:
<img src="https://bank.com/transfer?to=hacker&amount=1000">
# 用户访问 B 时,浏览器自动带 bank.com 的 cookie 发请求 -> 钱被转
防御
- SameSite Cookie:Set-Cookie 加 SameSite=Lax 或 Strict,第三方网站发请求不带 cookie。现代浏览器默认 Lax。
- CSRF Token:服务端生成随机 token 放表单,提交时校验。攻击者不知道 token,无法构造合法请求。
- 检查 Origin / Referer:只接受同源请求。
速率限制是安全防护
暴力破解、密码喷洒、API 滥用 —— 都靠速率限制兜底:
# 登录接口:
- 同一 IP 每分钟最多 5 次失败
- 同一账号每小时最多 10 次失败
- 失败超阈值锁账号 15 分钟 + 发邮件提醒
没有速率限制的登录接口,攻击者一天能跑几百万次密码尝试。
密钥管理
所有密码 / API Key / JWT secret / 数据库密码 都不能进代码仓库。常见方案:
- 环境变量:简单,但容器编排时仍要从某处来。
- HashiCorp Vault:专业密钥管理,支持动态密钥、自动轮换。
- 云厂商 KMS:AWS Secrets Manager、阿里云 KMS、GCP Secret Manager。
- Kubernetes Secrets + Sealed Secrets:K8s 环境的标配。
关键操作:定期轮换(每季度 / 半年)、泄漏立刻吊销、限制访问权限(只让需要的服务能读)。
写在最后
OWASP Top 10 不是 checklist,是"思考框架"。每写一段代码,问自己:"这里可能被注入吗?访问控制对吗?加密强吗?日志够吗?" 把这种思考变成习惯,你写的代码自然不容易出安全洞。
给一个职业建议:每个工程师都该学一遍 OWASP Top 10。不是为了变成安全工程师,而是因为大多数严重的线上安全事故都是普通工程师写出来的普通 bug。安全团队不可能 review 每行代码,但每个写代码的人能识别"这里有 SQL 注入"或"这里漏权限",事故率就会大幅下降。这是性价比最高的安全投资。
一图看懂
OWASP Top 10 一图看懂:
—— 别看了 · 2026