输出到 href 属性的 XSS 如何防御

1. 严格的白名单验证

这是最安全、最推荐的防御方法。不要试图去黑名单过滤,因为攻击者总能找到绕过的方法。相反,你应该只允许那些已知安全的协议和域名

  • 只允许安全的协议:只接受 httphttps 协议。所有其他协议,特别是 javascript:data:vbscript: 等,都应该被拒绝
  • 示例
    • 安全https://www.example.com
    • 不安全javascript:alert(1)

实现方式: 在后端代码中,你可以使用正则表达式或内置的 URL 解析函数来检查协议。例如,在 PHP 中可以这样做:

function is_safe_url($url) {
    $parsed_url = parse_url($url);
    if (!isset($parsed_url['scheme'])) {
        // 如果没有协议头,可能是相对路径,视为安全
        return true;
    }
    // 只允许 http 或 https 协议
    return in_array($parsed_url['scheme'], ['http', 'https']);
}

$user_input_url = $_GET['url'];
if (is_safe_url($user_input_url)) {
    // URL 安全,进行输出
    echo '<a href="' . htmlspecialchars($user_input_url) . '">Click Here</a>';
} else {
    // URL 不安全,拒绝或使用默认值
    echo '<a href="/default-page">Click Here</a>';
}

2. 对所有 URL 进行 HTML 实体编码

这是防御 XSS 的基本操作,但它不足以防御 href XSS。你仍然需要执行它,因为它能防止其他类型的 XSS 攻击htmlspecialchars()htmlentities()可以将<>"` 等特殊字符转换为实体,防止它们被解释为 HTML 标签

  • 正确做法:将 URL 进行白名单验证后,再进行 HTML 实体编码

    • 示例

      $safe_url = "https://example.com/page?param=<script>alert(1)</script>";
      echo '<a href="' . htmlspecialchars($safe_url) . '">Click Here</a>';
      
    • 结果:浏览器渲染为 <a href="https://example.com/page?param=<script>alert(1)</script>">Click Here</a>。即使 URL 中包含恶意代码,它也不会被执行。但如果 URL 是 javascript:alert(1),单独使用 htmlspecialchars() 是无效的

3. CSP

CSP 是一个强大的安全策略,可以从根本上限制页面可以加载和执行的资源。你可以设置一个 CSP 规则,明确禁止 javascript: 协议的 URI

  • 在 HTTP 响应头中添加Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; object-src 'none';

    这条规则不直接阻止 href 中的 javascript:,但它可以与不安全的内联脚本unsafe-inline)策略结合使用。一个更严格的 CSP 策略可以禁止内联脚本,从而让 javascript: 协议失效

  • 一个更有效的 CSP 规则Content-Security-Policy: default-src 'self'; script-src 'self';

    这条规则禁止了所有内联脚本,包括 javascript: 协议,从而提供了额外的保护层。不过,这可能会对你的网站功能造成影响,需要在部署前进行全面测试

Copyright © 版权信息 all right reserved,powered by Gitbook该文件修订时间: 2025-09-25 03:13:00

results matching ""

    No results matching ""