Web 安全实战:OWASP Top 10 漏洞详解与防御¶
为什么每个开发者都要懂 OWASP Top 10¶
OWASP(开放 Web 应用安全项目)的 Top 10 每几年更新一次,汇总了 Web 应用最常见的 10 类安全风险。漏洞不是测试工程师的事,是写代码的人的事——大部分漏洞的根因都在开发阶段。
本文挑选开发者最常踩的几类,讲原理、讲危害、讲防御。
一、注入(Injection)¶
原理¶
把用户输入当代码执行。最典型的是 SQL 注入:
-- 用户输入: ' OR '1'='1
SELECT * FROM users WHERE name = '' OR '1'='1';
-- 结果:绕过认证,返回所有用户
防御¶
# 错误:字符串拼接
sql = f"SELECT * FROM users WHERE name = '{name}'"
# 正确:参数化查询
cursor.execute(
"SELECT * FROM users WHERE name = %s", (name,)
)
黄金法则:任何查询都走参数化,不只对用户输入,对内部数据也一样。
命令注入¶
# 错误:拼接 shell 命令
os.system(f"ping {host}")
# 正确:用参数列表形式
subprocess.run(["ping", host])
二、失效的访问控制(Broken Access Control)¶
原理¶
用户能访问自己没有权限的资源。典型例子:
GET /api/orders/1001 # 正常
GET /api/orders/1002 # 换成别人的订单号 → 越权!
PUT /api/user/1/role # 直接改自己的角色为 admin
防御¶
- 服务端校验:每个接口都校验"当前用户是否有权操作这个资源",不能只在前端隐藏按钮
- 对象级授权:
user_id永远从会话取,不信任客户端传来的 ID - 默认拒绝:白名单路由,未显式允许的请求一律拒绝
- 水平越权 vs 垂直越权:水平(同权限用户互访资源)、垂直(低权限用户提权),都要测
三、XSS 跨站脚本¶
原理¶
把用户输入当 HTML/JS 执行:
<!-- 用户提交评论: <script>alert(document.cookie)</script> -->
<div class="comment">用户输入原样渲染</div>
后果:窃取 Cookie、会话劫持、钓鱼、挖矿。
防御¶
- 输出编码:渲染用户内容时转义 HTML 特殊字符(
<→<) - CSP 内容安全策略:限制页面能加载和执行的脚本来源
- HttpOnly Cookie:JS 读不到,降低窃取风险
- 富文本场景:用白名单过滤(如 DOMPurify),允许标签黑名单必被绕过
# 后端模板转义
{{ user_input }} # Jinja2/其他模板默认转义 ✅
{{ user_input|safe }} # 显式关闭转义,慎用 ⚠️
四、CSRF 跨站请求伪造¶
原理¶
用户已登录站点 A,此时访问恶意站点 B,B 里的表单/脚本向 A 发起请求,浏览器自动带上 A 的 Cookie,A 以为是用户本人的操作。
<!-- 恶意站点的陷阱图片 -->
<img src="https://bank.com/api/transfer?to=evil&amount=10000" />
防御¶
- CSRF Token:表单里带随机 token,服务端验证(主流框架内置,默认开启)
- SameSite Cookie:
Set-Cookie: ...; SameSite=Lax/Strict,跨站请求不带 Cookie - 校验 Origin/Referer:拒绝跨域来源的写操作
- 关键操作二次验证:转账、改密码要求输入密码或短信验证码
五、SSRF 服务端请求伪造¶
原理¶
服务端根据用户输入去请求内网资源:
# 用户传 url: http://169.254.169.254/latest/meta-data/ (云元数据接口)
requests.get(user_input_url)
攻击者利用服务端作为跳板,访问内网和云元数据(可能拿到云凭证)。
防御¶
- URL 白名单:只允许请求预先配置的域名/IP
- 禁止内网地址:过滤 127.0.0.0/8、10.0.0.0/8、172.16.0.0/12、169.254.0.0/16
- DNS rebinding 防护:解析后再校验 IP,防止域名解析到内网
- 不用时关掉重定向跟随(
allow_redirects=False按需开启)
六、安全配置错误¶
常见表现:
- 默认口令没改(admin/admin)
- 调试模式上线(报错信息泄露堆栈)
- 目录列表开放
- 多余端口/服务暴露
- 不必要的 HTTP 方法开启(TRACE、PUT)
检查清单¶
# 检查开放端口
ss -tlnp
# 检查 HTTP 头
curl -I https://your-site.com
# 期望有: X-Content-Type-Options: nosniff
# Strict-Transport-Security: ...
七、安全开发生命周期¶
在代码里做¶
- 依赖漏洞扫描(npm audit / pip-audit / Dependabot)
- 代码静态扫描(SonarQube、Semgrep)
- 上线前安全测试(至少把 Top 10 过一遍)
在架构里做¶
- 最小权限原则:服务账号只给必需权限
- 纵深防御:WAF + 代码过滤 + 审计日志
- 数据加密:传输 TLS,存储加密
结语¶
安全漏洞的修复成本随时间指数增长:开发时改一行代码,测试时改一个接口,上线后可能就是一次安全事故。把 OWASP Top 10 当作开发自检清单,每个接口交付前自查一遍,是成本最低的安全投入。