用户输入的javascript:伪协议怎么防不住XSS?

Mc.金利 阅读 27

在React项目里处理用户提交的留言内容时,发现如果用户输入类似javascript:alert(1)这样的内容,直接渲染后居然真的会执行脚本。虽然用了DOMPurify清理和转义特殊字符,但测试输入点击后点击链接还是会触发弹窗…


function MessageDisplay({ userContent }) {
  // 使用DOMPurified清理内容
  const sanitized = DOMPurify.sanitize(userContent, {
    ALLOWED_TAGS: ['a', 'br', 'strong']
  });
  
  return (
    <div 
      dangerouslySetInnerHTML={{ __html: sanitized }} 
    />
  );
}

尝试过设置Content-Security-Policy头和属性转义,但javascript:伪协议似乎能绕过过滤。这种情况下该怎么彻底阻断伪协议执行?单纯替换掉javascript:字符串会不会太粗暴?

我来解答 赞 4 收藏
二维码
手机扫码查看
1 条解答
轩辕子涵
你这情况我遇到过,React里用 dangerouslySetInnerHTML 渲染用户提交的内容本来就有风险,DOMPurify 默认配置对 javascript: 伪协议确实处理得不够彻底。

关键点有两个:

1. **DOMPurify 要启用 KEEP_CONTENTPOLICY**
默认不会过滤伪协议,得手动加配置:

DOMPurify.sanitize(userContent, {
ALLOWED_TAGS: ['a', 'br', 'strong'],
KEEP_CONTENTPOLICY: true
});


2. **强制移除 javascript: 协议**
即使启用了 KEEP_CONTENTPOLICY,默认也不会自动过滤 javascript:,你得加个自定义钩子:

DOMPurify.addHook('afterSanitizeAttributes', function(node) {
if (node.tagName === 'A' && node.hasAttribute('href')) {
const href = node.getAttribute('href').trim().toLowerCase();
if (href.startsWith('javascript:')) {
node.removeAttribute('href');
}
}
});


这样处理完之后,javascript:alert(1) 的链接就不会保留 href 属性了,点击也不会执行。

当然,最安全的做法还是:**尽量避免使用 dangerouslySetInnerHTML**,改成文本渲染,富文本部分用白名单控制。如果只是展示留言,直接用 React 组件结构渲染用户内容会更安全。

XSS 真的防不胜防,特别是带伪协议的链接,光靠 sanitizer 不够,前端加一层清理钩子是必须的。单纯替换 javascript: 也不算粗暴,但容易漏掉变形绕过的 payload,还是结合 sanitizer 钩子更稳妥。
点赞 10
2026-02-04 23:01