前端安全系列(一):如何防止XSS攻击?
字数 2922 2025-08-18 11:37:41

XSS攻击全面防护指南

一、XSS攻击概述

XSS(Cross-Site Scripting,跨站脚本攻击)是一种代码注入攻击,攻击者通过在目标网站上注入恶意脚本,使之在用户的浏览器上运行。XSS的本质是:恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行。

XSS攻击的危害

  • 窃取用户敏感信息(如Cookie、SessionID)
  • 冒充用户执行操作
  • 传播恶意内容
  • 发起"XSS蠕虫"攻击

二、XSS攻击分类

1. 存储型XSS

  • 存储区:后端数据库
  • 插入点:HTML
  • 攻击流程
    1. 攻击者提交恶意代码到数据库
    2. 用户访问页面时从数据库取出恶意代码
    3. 浏览器执行恶意代码

常见场景:论坛发帖、商品评论、用户私信等用户可提交持久化数据的场景。

2. 反射型XSS

  • 存储区:URL
  • 插入点:HTML
  • 攻击流程
    1. 攻击者构造含恶意代码的URL
    2. 用户点击URL,服务端取出恶意代码返回
    3. 浏览器执行恶意代码

常见场景:网站搜索、跳转等通过URL传递参数的功能。

3. DOM型XSS

  • 存储区:后端数据库/前端存储/URL
  • 插入点:前端JavaScript
  • 攻击流程
    1. 攻击者构造含恶意代码的URL
    2. 用户点击URL
    3. 前端JS取出URL中的恶意代码并执行

与前两种的区别:DOM型XSS完全在前端完成,不经过服务端处理。

三、XSS攻击的注入方式

  1. 在HTML中内嵌的文本中,以<script>标签形式注入
  2. 在内联JavaScript中,突破字符串、变量等限制
  3. 在标签属性中,通过引号突破属性值限制
  4. hrefsrc等属性中,包含javascript:等可执行代码
  5. onloadonerroronclick等事件中注入代码
  6. style属性和标签中,包含类似background-image:url("javascript:...");的代码
  7. style属性和标签中,包含类似expression(...)的CSS表达式代码

四、XSS防御策略

1. 输入过滤的局限性

  • 前端过滤可被绕过
  • 后端过滤可能导致乱码问题
  • 不同上下文需要不同的转义规则

建议:仅对明确类型的输入(数字、URL、电话等)进行过滤

2. 存储型和反射型XSS防御

(1) 纯前端渲染

  • 浏览器先加载静态HTML
  • 通过Ajax加载业务数据
  • 明确告诉浏览器设置内容的类型(.innerText.setAttribute等)

优点:有效隔离代码和数据
注意:仍需防范DOM型XSS

(2) HTML转义

使用完善的转义库,针对不同上下文采用不同转义规则:

上下文 转义函数示例 转义内容
HTML标签文字内容 Encode.forHtml() &, <, >, ", ', /
HTML属性值 Encode.forHtml() 同上
CSS属性值 Encode.forCssString() 防止突破CSS字符串
CSS URL Encode.forCssUrl() 防止注入恶意URL
JavaScript字符串 Encode.forJavaScript() 防止突破JS字符串
内联JSON Encoder.forJavaScript(data.to_json) 转义U+2028、U+2029、<
URL参数 Encode.forUriComponent() URL编码
URL路径 Encode.forUriComponent() URL编码

3. DOM型XSS防御

  • 避免使用.innerHTML.outerHTMLdocument.write()
  • 使用.textContent.setAttribute()等安全API
  • 避免将不可信数据拼接到以下场景:
    • 内联事件监听器(onclick等)
    • <a>标签的href属性
    • eval()setTimeout()setInterval()等可执行字符串的API

4. 其他防御措施

(1) Content Security Policy (CSP)

  • 禁止加载外域代码
  • 禁止外域提交
  • 禁止内联脚本执行
  • 禁止未授权的脚本执行

(2) 输入内容长度控制

对不受信任的输入限制合理长度,增加攻击难度

(3) 安全措施

  • HTTP-only Cookie:防止JS读取敏感Cookie
  • 验证码:防止脚本冒充用户操作

五、XSS检测方法

1. 手动检测

使用通用XSS攻击字符串测试,例如:

jaVasCript:oNcliCk=alert() )//%0D%0A%0d%0a//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert()//>\x3e

2. 自动扫描工具

  • Arachni
  • Mozilla HTTP Observatory
  • w3af

六、最佳实践原则

  1. 利用模板引擎

    • 开启自带的HTML转义功能
    • ejs使用<%= data %>而非<%- data %>
    • doT.js使用{{! data }}而非{{= data }}
    • FreeMarker确保版本>2.3.24
  2. 避免内联事件

    • 使用.addEventListener()而非onclick="go('{{action}}')"
  3. 避免拼接HTML

    • 使用createElementsetAttribute
    • 或使用Vue/React等框架
  4. 保持警惕

    • 特别注意DOM属性、链接等位置
  5. 增加攻击难度

    • 使用CSP、输入长度限制等
  6. 主动检测

    • 定期使用XSS字符串和扫描工具检测

七、常见误区

  1. 误区一:XSS防范只是后端的责任

    • 事实:存储型和反射型是后端责任,DOM型是前端责任
  2. 误区二:所有数据都通过同一个过滤函数转义

    • 事实:不同上下文需要不同转义规则
  3. 误区三:转义应该在提交用户输入时进行

    • 事实:转义应在输出HTML时进行

八、真实案例

1. QQ邮箱反射型XSS

  • 漏洞点:uindomain参数未转义直接输出
  • 攻击URL:包含恶意脚本的URL参数
  • 结果:窃取用户Cookie

2. 新浪微博名人堂反射型XSS

  • 漏洞点:URL内容未过滤直接输出
  • 攻击方式:XSS蠕虫,诱导更多人点击
  • 结果:利用受害者身份发布恶意内容

九、进阶防护:Automatic Context-Aware Escaping

概念:模板引擎自动分析插入点上下文,应用合适的转义规则。

支持引擎:

  1. Go html/template
  2. Google Closure Templates

示例:

<html>
  <head>
    <meta charset="UTF-8">
    <title>{{.title}}</title>
  </head>
  <body>
    <a href="{{.url}content}}</a>
  </body>
</html>

引擎自动转换为:

<html>
  <head>
    <meta charset="UTF-8">
    <title>{{.title | htmlescaper}}</title>
  </head>
  <body>
    <a href="{{.url | urlescaper | attrescaper}content | htmlescaper}}</a>
  </body>
</html>

十、总结

XSS防御是系统工程,需要前后端协作:

  1. 后端:处理存储型和反射型XSS
  2. 前端:处理DOM型XSS
  3. 共同:实施CSP等安全策略

关键点:

  • 理解不同上下文的不同转义需求
  • 使用成熟的转义库而非自己实现
  • 避免危险的API(如innerHTML
  • 定期检测和修复漏洞
XSS攻击全面防护指南 一、XSS攻击概述 XSS(Cross-Site Scripting,跨站脚本攻击)是一种代码注入攻击,攻击者通过在目标网站上注入恶意脚本,使之在用户的浏览器上运行。XSS的本质是:恶意代码未经过滤,与网站正常的代码混在一起;浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行。 XSS攻击的危害 窃取用户敏感信息(如Cookie、SessionID) 冒充用户执行操作 传播恶意内容 发起"XSS蠕虫"攻击 二、XSS攻击分类 1. 存储型XSS 存储区 :后端数据库 插入点 :HTML 攻击流程 : 攻击者提交恶意代码到数据库 用户访问页面时从数据库取出恶意代码 浏览器执行恶意代码 常见场景:论坛发帖、商品评论、用户私信等用户可提交持久化数据的场景。 2. 反射型XSS 存储区 :URL 插入点 :HTML 攻击流程 : 攻击者构造含恶意代码的URL 用户点击URL,服务端取出恶意代码返回 浏览器执行恶意代码 常见场景:网站搜索、跳转等通过URL传递参数的功能。 3. DOM型XSS 存储区 :后端数据库/前端存储/URL 插入点 :前端JavaScript 攻击流程 : 攻击者构造含恶意代码的URL 用户点击URL 前端JS取出URL中的恶意代码并执行 与前两种的区别:DOM型XSS完全在前端完成,不经过服务端处理。 三、XSS攻击的注入方式 在HTML中内嵌的文本中,以 <script> 标签形式注入 在内联JavaScript中,突破字符串、变量等限制 在标签属性中,通过引号突破属性值限制 在 href 、 src 等属性中,包含 javascript: 等可执行代码 在 onload 、 onerror 、 onclick 等事件中注入代码 在 style 属性和标签中,包含类似 background-image:url("javascript:..."); 的代码 在 style 属性和标签中,包含类似 expression(...) 的CSS表达式代码 四、XSS防御策略 1. 输入过滤的局限性 前端过滤可被绕过 后端过滤可能导致乱码问题 不同上下文需要不同的转义规则 建议 :仅对明确类型的输入(数字、URL、电话等)进行过滤 2. 存储型和反射型XSS防御 (1) 纯前端渲染 浏览器先加载静态HTML 通过Ajax加载业务数据 明确告诉浏览器设置内容的类型( .innerText 、 .setAttribute 等) 优点 :有效隔离代码和数据 注意 :仍需防范DOM型XSS (2) HTML转义 使用完善的转义库,针对不同上下文采用不同转义规则: | 上下文 | 转义函数示例 | 转义内容 | |--------|--------------|----------| | HTML标签文字内容 | Encode.forHtml() | & , < , > , " , ' , / | | HTML属性值 | Encode.forHtml() | 同上 | | CSS属性值 | Encode.forCssString() | 防止突破CSS字符串 | | CSS URL | Encode.forCssUrl() | 防止注入恶意URL | | JavaScript字符串 | Encode.forJavaScript() | 防止突破JS字符串 | | 内联JSON | Encoder.forJavaScript(data.to_json) | 转义U+2028、U+2029、 < 等 | | URL参数 | Encode.forUriComponent() | URL编码 | | URL路径 | Encode.forUriComponent() | URL编码 | 3. DOM型XSS防御 避免使用 .innerHTML 、 .outerHTML 、 document.write() 使用 .textContent 、 .setAttribute() 等安全API 避免将不可信数据拼接到以下场景: 内联事件监听器( onclick 等) <a> 标签的 href 属性 eval() 、 setTimeout() 、 setInterval() 等可执行字符串的API 4. 其他防御措施 (1) Content Security Policy (CSP) 禁止加载外域代码 禁止外域提交 禁止内联脚本执行 禁止未授权的脚本执行 (2) 输入内容长度控制 对不受信任的输入限制合理长度,增加攻击难度 (3) 安全措施 HTTP-only Cookie:防止JS读取敏感Cookie 验证码:防止脚本冒充用户操作 五、XSS检测方法 1. 手动检测 使用通用XSS攻击字符串测试,例如: 2. 自动扫描工具 Arachni Mozilla HTTP Observatory w3af 六、最佳实践原则 利用模板引擎 : 开启自带的HTML转义功能 ejs使用 <%= data %> 而非 <%- data %> doT.js使用 {{! data }} 而非 {{= data }} FreeMarker确保版本>2.3.24 避免内联事件 : 使用 .addEventListener() 而非 onclick="go('{{action}}')" 避免拼接HTML : 使用 createElement 、 setAttribute 或使用Vue/React等框架 保持警惕 : 特别注意DOM属性、链接等位置 增加攻击难度 : 使用CSP、输入长度限制等 主动检测 : 定期使用XSS字符串和扫描工具检测 七、常见误区 误区一 :XSS防范只是后端的责任 事实:存储型和反射型是后端责任,DOM型是前端责任 误区二 :所有数据都通过同一个过滤函数转义 事实:不同上下文需要不同转义规则 误区三 :转义应该在提交用户输入时进行 事实:转义应在输出HTML时进行 八、真实案例 1. QQ邮箱反射型XSS 漏洞点: uin 、 domain 参数未转义直接输出 攻击URL:包含恶意脚本的URL参数 结果:窃取用户Cookie 2. 新浪微博名人堂反射型XSS 漏洞点:URL内容未过滤直接输出 攻击方式:XSS蠕虫,诱导更多人点击 结果:利用受害者身份发布恶意内容 九、进阶防护:Automatic Context-Aware Escaping 概念:模板引擎自动分析插入点上下文,应用合适的转义规则。 支持引擎: Go html/template Google Closure Templates 示例: 引擎自动转换为: 十、总结 XSS防御是系统工程,需要前后端协作: 后端:处理存储型和反射型XSS 前端:处理DOM型XSS 共同:实施CSP等安全策略 关键点: 理解不同上下文的不同转义需求 使用成熟的转义库而非自己实现 避免危险的API(如 innerHTML ) 定期检测和修复漏洞