威胁与攻击向量
Kill Chain、ATT&CK、钓鱼、OWASP Top 10。
Web 攻击剖析:SQL 注入、XSS、CSRF、SSRF 与 OWASP Top 10
这一课你将能做到
- 在 DVWA 靶机上亲手复现 SQL 注入、XSS、CSRF、SSRF 四类经典攻击
- 对每一类攻击给出对应的 Spring Boot 防御代码与配置
- 用 OWASP Top 10 作为自查清单,定位自己平台的高危缺口
为什么要学
这四类攻击统治了 Web 漏洞榜单二十多年,至今仍在 OWASP Top 10 里。区别只是当年的 1' or '1'='1 换成了今天的 JSON API、ORM 拼接和云元数据接口。你写的每一行 queryWrapper、每一个接收 URL 的接口,都是攻防现场。
人话:SQL 注入是「把数据当代码执行」,XSS 是「把代码当数据混进页面」,CSRF 是「借刀杀人——用你的身份发请求」,SSRF 是「让服务器替我敲门」。
先建立图像
SQL注入: 输入 → [字符串拼接进SQL] → 数据库执行 → 数据当代码
XSS: 输入 → [原样写进HTML] → 浏览器执行 → 数据当代码
CSRF: 恶意页 → [借用户Cookie发请求] → 服务端误认合法 → 身份被借用
SSRF: 恶意URL → [服务端发请求] → 打内网/云元数据 → 服务器变跳板
共同根因只有一个:信任了不可信输入。所以防御哲学也统一:数据与代码严格分离 + 服务端不信任任何客户端。
跟着做
再次强调:以下全部操作只针对步骤 0 部署在你本机的 DVWA,这是官方授权的漏洞练习靶机。
步骤 0:启动靶场
docker run --rm -it -d -p 80:80 vulnerables/web-dvwa
# 浏览器 http://localhost,admin/password 登录,Reset Database
# DVWA Security 先保持 low,复现后再切 high 看防御差异
步骤 1:SQL 注入(SQL Injection 页)
输入 1 正常返回用户名;输入 ' OR '1'='1 返回全部用户——因为后端把输入拼进了查询:
SELECT first_name,last_name FROM users WHERE user_id = '输入';
-- 输入 1' or '1'='1 后变成:
-- ... WHERE user_id = '1' or '1'='1' → 恒真,全表返回
进阶:1' UNION SELECT user,password FROM users# 直接拖库。切到 high 难度再看,参数化后这些输入只是普通字符串。
步骤 2:XSS(XSS Reflected 页)
输入 <script>alert(document.cookie)</script>,页面直接弹回你的 Cookie。反射型靠诱导点击,存储型(XSS Stored 页)把恶意脚本存进留言板,每个访问者都中招,危害更大。
步骤 3:CSRF(CSRF 页)
<!-- 攻击页里藏一张自动提交的表单,受害者带着自己的 Cookie 访问即触发 -->
<img src="http://localhost/vulnerabilities/csrf/?password_new=hacked&password_conf=hacked" />
<!-- 受害者的浏览器自动带上 DVWA Cookie,密码被改而本人无感 -->
步骤 4:SSRF(本站文件包含页或自建演示接口)
# 假设平台有「通过 URL 拉取头像」的功能,攻击者提交:
curl "http://localhost/vulnerabilities/fi/?file=http://192.168.56.1:8080/actuator/env"
# 服务端替攻击者请求了内网地址 —— 云环境下打 http://169.254.169.254 可偷云凭证
步骤 5:写对应的 Spring Boot 防御
// ① SQL 注入:参数化(JdbcTemplate / MyBatis #{} / JPA 参数绑定)
jdbcTemplate.query("SELECT * FROM users WHERE id = ?", rowMapper, id);
// ② XSS:输出编码 + 输入校验 + 富文本白名单(OWASP Java HTML Sanitizer)
PolicyFactory policy = Sanitizers.FORMATTING.and(Sanitizers.LINKS);
String safe = policy.sanitize(untrustedHtml);
// ③ CSRF:Spring Security 默认开启 CSRF token;纯 API 可改用 SameSite=Strict Cookie
http.csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()));
// ④ SSRF:URL 白名单校验 + 禁内网地址