2025-11-27-前端安全-关于XSS与CRSF及其相关对策

文章发布时间:

最后更新时间:

页面浏览: 加载中...

跨站脚本攻击(XSS)和跨站请求伪造(CSRF)

跨站脚本攻击(Cross-Site Scripting,简称 XSS)和跨站请求伪造(Cross-Site Request Forgery,简称 CSRF 或 XSRF)是 Web 应用中最常见的两种安全漏洞。尽管名称相似,但攻击原理、影响和防御方式完全不同。

1. 跨站脚本攻击(XSS)

定义:XSS 是一种代码注入攻击,攻击者将恶意客户端脚本(通常为 JavaScript)注入到网页中,当受害者访问该页面时,恶意脚本在受害者的浏览器中执行,从而窃取信息或执行恶意操作。

分类:XSS 攻击主要分为三种类型。首先是反射型 XSS(Reflected XSS),恶意脚本通过 URL 参数、表单提交等反射回响应页面,常用于钓鱼攻击,例如用户点击含有<script>alert(document.cookie)</script>的链接。其次是存储型 XSS(Stored/Persistent XSS),恶意脚本被永久存储在服务器(如数据库中的评论、帖子),所有访问该内容的用户均受影响,危害最大。最后是基于 DOM 的 XSS(DOM-based XSS),恶意脚本通过客户端 JavaScript 操作 DOM 注入,通常不涉及服务器反射。

攻击后果:XSS 攻击可能导致多种严重后果。攻击者可以窃取 Cookie、Session Token,导致会话劫持;伪造请求、钓鱼、键盘记录;还可以对页面进行篡改(Defacement)。

防御措施:针对 XSS 攻击有多种防御措施。输出编码(Output Encoding)是在 HTML、JavaScript、CSS、URL 等上下文中对用户输入进行适当转义(如使用 DOMPurify 净化 HTML);内容安全策略(Content Security Policy, CSP)通过 HTTP 头限制脚本来源;输入验证则是严格验证和过滤用户输入;HttpOnly Cookie 可以防止 JavaScript 访问 Cookie;使用安全库如 DOMPurify、OWASP Java Encoder 等也是有效手段。

详细防御策略:在具体实施中,HTML 编码将特殊字符(<、>、&、”、’)转换为 HTML 实体,防止浏览器将其解释为标签。JavaScript 编码在 JavaScript 上下文中使用用户输入前,将特殊字符转义为 JavaScript 字符串或正则表达式格式。CSS 编码在 CSS 上下文中使用用户输入时,需要转义特殊字符。URL 编码则对 URL 参数进行编码,确保 URL 安全。

CSP 实施示例可以通过 HTTP 头设置:

1
2
3
Content-Security-Policy: default-src 'self';
script-src 'self' 'unsafe-inline' https://trusted-cdn.example.com;
object-src 'none'; frame-ancestors 'none';

也可以在 HTML 中设置

1
2
3
4
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self' 'unsafe-inline';"
/>

使用模板引擎的安全特性也很重要,如 Jinja2、Handlebars 等模板引擎通常内置 XSS 防护,使用时避免使用”raw”或”unsafe”过滤器。同时需要进行严格的输入验证,不仅在服务端验证输入,也要在客户端进行验证(虽然客户端验证可被绕过,但可以改善用户体验)。

2. 跨站请求伪造(CSRF)

定义:CSRF 是一种利用用户已认证身份的攻击。攻击者诱导已登录的用户在不知情情况下向目标网站发送恶意请求,利用浏览器自动携带 Cookie 的特性执行敏感操作。

攻击原理:首先,用户已登录目标网站(如银行网站),浏览器保存了认证 Cookie。然后,攻击者通过钓鱼邮件、恶意网站诱导用户访问含有恶意表单或图像的页面,例如 HTML 中的<img src="https://bank.com/transfer?amount=1000&to=attacker">
最后,浏览器自动携带 Cookie 发送请求,完成转账等操作

攻击后果:CSRF 攻击可能导致未经授权执行敏感操作(如转账、修改密码、删除账户)。虽然它不直接窃取数据,但可利用用户权限造成破坏。

防御措施:针对 CSRF 有多种防御措施。CSRF Token(同步器令牌)是在表单或请求中加入服务器生成的随机 Token,服务器验证 Token 是否匹配且有效,主流框架(如 Django、Spring、Rails)内置支持。SameSite Cookie 是设置 Cookie 的 SameSite 属性(Lax 或 Strict),限制跨站请求携带 Cookie,其中 SameSite=Lax 允许顶级导航(如 GET 链接),阻止大多数 CSRF;SameSite=Strict 完全阻止跨站请求携带 Cookie。双重提交 Cookie(Double Submit Cookie)是将 Token 同时存入 Cookie 和表单,服务器比对两者(适用于无状态应用)。验证 Referer/Origin 头是检查请求来源是否合法(可被伪造或禁用,不推荐单独使用)。使用安全的 HTTP 方法是敏感操作仅允许 POST、PUT、DELETE 等非幂等方法。

详细防御策略:CSRF Token 的实现包括几个步骤:服务器生成随机的 CSRF Token(如使用加密安全的随机数生成器);将 Token 放入表单隐藏字段或 HTTP 头中;用户提交请求时,服务器验证 Token 是否匹配且未过期;Token 应在每次会话或关键操作后更新。

SameSite Cookie 设置示例包括设置 SameSite 属性:

1
2
3
4
5
Set-Cookie: sessionId=abc123;
Path=/;
HttpOnly;
SameSite=Strict
Set-Cookie: sessionId=abc123; Path=/; HttpOnly; SameSite=Lax

自定义请求头验证要求所有 API 请求包含自定义头部(如 X-Requested-With 或 X-CSRF-Token),因为浏览器在跨站请求中不会自动添加这些头部。验证码机制对高风险操作(如修改密码、转账)要求用户输入验证码或进行二次确认。登出确认在登出页面添加确认步骤,防止攻击者诱导用户登出。

XSS 与 CSRF 的对比总结

项目 XSS CSRF
攻击目标 浏览器中的信任(执行恶意脚本) 网站对用户的信任(利用已认证会话)
是否需要注入代码 是(注入 JavaScript) 否(仅诱导发送请求)
主要危害 窃取数据、会话劫持、页面篡改 伪造用户操作(如转账、改密)
典型场景 用户输入未过滤的评论、搜索框 登录后访问恶意网站
核心防御 输出编码、CSP、输入验证 CSRF Token、SameSite Cookie
是否可相互利用 XSS 可绕过 CSRF 防御(直接读 Token) CSRF 无法直接引发 XSS

综合防御策略:在实际安全防护中,需要采用多种策略。分层防御是结合多种防御措施,而不是依赖单一方法。安全默认值是在系统设计时就考虑安全因素,而不是事后补救。定期安全审计使用自动化工具和手动测试来识别潜在的安全漏洞。开发者培训提高团队对安全问题的认识和防范能力。监控和日志记录可疑活动,及时发现攻击尝试。

实际应用示例:在实际开发中,我们通常会组合使用多种防御策略。例如 JavaScript 代码示例中,createSecureForm 函数首先验证输入数据,然后对输出进行编码,最后添加 CSRF Token,这样就结合了多种安全措施。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 一个安全的表单处理示例
function createSecureForm(data) {
// 1. 验证输入数据
if (!isValidInput(data)) {
throw new Error("Invalid input");
}

// 2. 输出编码
const safeData = encodeForHTML(data);

// 3. 添加 CSRF Token
const csrfToken = getCSRFToken();

return `
<form method="POST" action="/submit">
<input type="hidden" name="csrf_token" value="${csrfToken}">
<div>${safeData}</div>
<button type="submit">提交</button>
</form>
`;
}

// 通过 CSP 策略进一步保护
// Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';

攻击者若成功执行 XSS,可轻松绕过 CSRF Token(通过脚本读取并发送 Token),因此,在 Web 安全开发中,必须同时防御这两种漏洞。