在前端安全领域,XSS(跨站脚本攻击,Cross-Site Scripting) 绝对是"头号公敌"。它允许攻击者将恶意脚本注入到网页中,当其他用户浏览该页面时,脚本会在用户的浏览器中执行。这就好比一个坏人(黑客)在超市(网页)的货架上放了一张虚假的优惠券(恶意脚本),当顾客(用户)拿起来看时,优惠券上的咒语就生效了,可能会偷走顾客的钱包(Cookie)或者替顾客下单(执行非法操作)。
为了帮你彻底搞定这个问题,我将从攻击原理、三大类型、危害 以及防御方案这几个维度为你详细拆解。
XSS 攻击的三大类型
XSS 攻击主要分为三类,了解它们的区别是防御的第一步
|------------|--------------------------------------|-----------------------------------------------|----------------------------------|
| 类型 | 反射型 XSS | 存储型 XSS | DOM 型 XSS |
| 别名 | 非持久型 XSS | 持久型 XSS | 基于 DOM 的 XSS |
| 原理 | 恶意脚本作为请求的一部分发送给服务器,服务器解析后立即"反射"回响应中。 | 恶意脚本被永久存储在目标服务器(如数据库、评论区)。 | 漏洞完全存在于前端 JavaScript 代码中,不经过服务器。 |
| 触发方式 | 通常需要用户点击诱导链接(如钓鱼邮件)。 | 用户访问正常的页面时就会触发。 | 用户访问特定 URL 或交互时触发。 |
| 危害程度 | 中(需要诱骗点击) | 高(影响所有访问者) | 中/高(取决于利用方式) |
| 例子 | http://example.com?search=alert(1) | 在论坛发帖内容包含 <img src=x onerror=stealCookie()> | location.hash 未经过滤直接写入 innerHTML |
XSS 会造成什么危害
不要觉得弹个窗(alert(1))只是恶作剧,攻击者可以利用 XSS 做非常多危险的事情:
- 窃取用户凭证:获取 Cookie、LocalStorage 中的登录令牌(Token),直接冒充用户身份。
- 劫持操作:模拟用户点击、发帖、转账。
- 键盘记录:在页面中注入脚本,记录用户的键盘输入(如密码)。
- 钓鱼攻击:动态修改页面内容(如修改银行转账收款人),诱导用户输入敏感信息。
- 内网探测:利用用户的浏览器作为跳板,扫描企业内部网络。
核心防御方案(实战篇)
防御 XSS 的核心思想只有两个字:"过滤" 和 "转义"。
1. 输入过滤与净化(Input Sanitization)
原则:永远不要信任用户的输入。
- 白名单机制 :对于富文本输入(如评论、文章),不要试图去"删除"危险标签(黑名单机制很容易被绕过,比如 onerror 拼成 onerror),而是建立白名单。
- 使用专业库 :千万不要自己写正则表达式去解析 HTML,非常容易出错。
- 推荐使用 DOMPurify
- 原理:只允许安全的标签(如 <p>, <b>, <img>)和属性(如 src, alt),自动移除 <script>、onerror、javascript: 协议等危险内容。
2. 输出编码(Output Encoding)
原则:在正确的上下文(Context)中输出数据。
- HTML 上下文:将 < 转义为 <,> 转义为 >。可以使用 textContent 代替 innerHTML。
- JavaScript 上下文:如果数据是插入到 <script> 标签内的变量中,需要进行 Unicode 转义。
- URL 上下文:使用 encodeURIComponent。
- CSS 上下文:尽量避免用户输入直接进入 CSS,如果必须,要严格过滤。
3. 内容安全策略(CSP, Content Security Policy)
这是防御 XSS 的"终极保险"。
- 原理:通过 HTTP 响应头(Content-Security-Policy)告诉浏览器,哪些资源是可以加载的,哪些是禁止的。
- 效果 :
- 禁止加载内联脚本(...)。
- 禁止使用 eval()。
- 只允许加载指定域名的 JS/CSS 文件。
- 配置示例:
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted-cdn.com; object-src 'none';
- 即使黑客成功注入了 <script> 标签,浏览器也会因为 CSP 的限制而拒绝执行它。
4. Cookie 安全设置
即使发生了 XSS,也要让黑客拿不到最重要的东西。
- HttpOnly:设置 Cookie 时加上 HttpOnly 属性。这样 JavaScript(包括 XSS 脚本)就无法通过 document.cookie 读取到该 Cookie,只能通过 HTTP 请求头发送。
- Secure:仅在 HTTPS 下传输。
- SameSite:防止 CSRF 攻击,通常设置为 Strict 或 Lax。
总结:防御 XSS 的最佳实践清单
- 富文本处理 :必须使用 DOMPurify 等库进行服务端和客户端的双重净化。
- 普通文本展示:优先使用框架的文本插值(如 Vue 的 {{}},React 的 {})或 DOM 的 textContent,它们默认会转义 HTML。
- HTTP 头 :务必配置 CSP 策略,并开启 X-XSS-Protection(虽然现代浏览器逐渐弃用,但作为兼容也是一种补充)。
- Cookie :关键 Cookie 务必设置 HttpOnly。
- 框架安全:使用现代前端框架(React/Vue/Angular),它们在设计上就内置了很多防御机制(如 React 默认对属性进行转义),但要注意避免滥用 dangerouslySetInnerHTML 或 v-html。
XSS 防御是一场持久战,核心在于保持警惕:只要数据来自用户,就必须假设它是恶意的,并在存储和展示的每一个环节进行处理。