如何防范事件属性中的XSS漏洞?比如onclick里被注入脚本?

Prog.晓芳 阅读 26

最近在做用户评论功能时,允许用户自定义事件属性(比如onclick),但测试时发现如果输入”onclick=alert(1)”会被直接执行。我尝试过滤了常见的事件属性名,但测试人员用”onCLick”或者编码绕过还是能触发。有没有更可靠的过滤方法?

我来解答 赞 8 收藏
二维码
手机扫码查看
2 条解答
奕冉~
奕冉~ Lv1
这个问题的关键是不能简单地依赖黑名单过滤,因为事件属性名和编码方式太多,根本防不胜防。你已经发现测试人员可以通过大小写混合、HTML实体编码等方式绕过简单的过滤,这就说明黑名单策略不可靠。

### 正确的解决方案有两个方向:

#### ✅ 方案一:**白名单允许的属性 + 属性值转义**
如果你的业务中允许用户输入的属性是有限的,比如只允许 hreftarget,那么最安全的方式是:

1. **严格白名单机制**:只允许指定属性。
2. **属性值全部转义处理**:不管属性名是否合法,属性值都进行 HTML 转义。

例如 PHP 中可以这样做:

<?php
function sanitize_attributes($input) {
// 白名单属性
$allowed_attributes = ['href', 'target', 'title'];
$dom = new DOMDocument();
$dom->loadHTML($input, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

foreach ($dom->getElementsByTagName('*') as $tag) {
foreach ($tag->attributes as $attr) {
$attrName = strtolower($attr->nodeName);
if (!in_array($attrName, $allowed_attributes)) {
$tag->removeAttribute($attr->nodeName);
} else {
// 对属性值做 HTML 转义
$safeValue = htmlspecialchars($attr->nodeValue, ENT_QUOTES, 'UTF-8');
$tag->setAttribute($attr->nodeName, $safeValue);
}
}
}

return $dom->saveHTML();
}


这样处理后,onCLick="alert(1)" 会被识别为非法属性直接移除。

#### ✅ 方案二:**使用 HTML 解析器 + 安全策略(推荐)**

如果允许的属性比较复杂,或者你希望更通用、安全、可维护,推荐使用 HTML 净化库,比如 [HTML Purifier](http://htmlpurifier.org/)(PHP),它内部已经处理了各种绕过手段,包括大小写、编码、伪协议等。

安装 HTML Purifier:

composer require ezyang/htmlpurifier


使用示例:

<?php
require_once 'vendor/autoload.php';

$clean_html = HTMLPurifier::getInstance()->purify($dirty_html);
echo $clean_html;


HTML Purifier 内部做了很多事:
- 识别各种编码绕过
- 过滤所有非法事件属性
- 支持自定义配置白名单

### 🔍 为什么这样做有效?

1. **DOMDocument + 白名单**:通过操作 DOM,我们可以准确识别标签和属性,避免字符串替换带来的误判。
2. **转义属性值**:即使属性名合法,值也可能是危险的,所以必须转义输出。
3. **使用成熟库**:XSS 过滤不是小事,各种绕过手段层出不穷,用成熟的库是最省心的方式。

### 🧪 测试建议

你可以尝试用这些 payload 来验证你的过滤是否有效:

<!-- 大小写绕过 -->
<div onCLick="alert(1)">Click me</div>

<!-- HTML 实体编码绕过 -->
<div onmouseover="&#x61;lert(1)">Hover me</div>

<!-- URL 编码绕过 -->
<a href="javascript:alert(1)">XSS Link</a>


确保这些在你的输出中都被清除或转义。

### ❌ 不推荐的做法

- 用 str_replace 替换关键词(很容易绕过)
- 用正则表达式匹配 on.*=(太容易绕过,比如加空格、换行、编码等)
- 只对属性值做简单的 htmlspecialchars 而不限制属性名

---

总结:XSS 是个大坑,不能靠运气防御。推荐你使用 HTML Purifier 或者自己实现完整的 DOM 过滤逻辑,这样才能真正把风险降到最低。
点赞 6
2026-02-03 14:07
程序猿名赫
这种场景下,允许用户自定义事件属性本身就非常危险,最好的办法是从源头避免。如果非要做,建议完全禁止解析任何事件属性,比如 onclickonmouseover 这些统统干掉。

你可以用服务端的 HTML 转义库来过滤用户输入的内容,推荐使用白名单机制,只保留你信任的标签和属性,其他一概丢掉。比如 PHP 里的 HTMLPurifier 或者 Java 的 OWASP Java HTML Sanitizer 都很不错。

另外,如果你真的需要支持一些交互功能,可以用更安全的方式实现,比如把用户的动作绑定到后端生成的事件上,而不是直接让用户输入事件属性。这样既能满足需求,又不会给 XSS 留机会。

实在要手写过滤逻辑的话,可以参考下面这个简单的正则(但不保证完美):
function sanitize_input($input) {
// 移除所有以 "on" 开头的属性
$sanitized = preg_replace('/onw+="[^"]*"/i', '', $input);
return htmlspecialchars($sanitized, ENT_QUOTES, 'UTF-8');
}


不过说实话,手动写这种东西很容易漏掉情况,还是推荐用现成的库比较靠谱。XSS 这玩意儿太狡猾了,别以为简单过滤一下就能高枕无忧,测试人员分分钟能找到新姿势绕过你。
点赞 5
2026-01-31 12:03