strip_tags() 仅移除标签外壳,不清理危险属性,无法防御 xss;正则清洗需覆盖大小写、空白、引号等绕过;htmlpurifier 是唯一可靠方案;输出上下文决定转义方式,不可统一过滤。

strip_tags() 保留白名单标签但不处理属性风险
strip_tags() 看似能“保留安全标签”,但它只删标签外壳,不管里面有没有 onclick、onerror、href="javascript:" 这类危险属性。比如:@#@#@#@#@#@#@#@#@#@0 经 strip_tags($str, '<a>')</a> 处理后,<a></a> 标签还在,但属性没被清理,照样触发 XSS。
它适合纯展示型文本(如评论摘要),但不能用于富文本输入场景。如果你需要保留 <p></p>、<strong></strong> 等标签,又怕属性注入,就不能只靠 strip_tags()。
正则替换 on* 事件和 javascript: 协议必须写全匹配模式
用 preg_replace() 清洗属性时,常见错误是只匹配 onclick=,漏掉大小写变体(OnClick)、空格绕过(onclick =)、引号省略(onclick=test())或换行截断(on\nerror=)。
推荐写法(带修饰符 i 和 s):
preg_replace('/\s+(on\w+|href)\s*=\s*([\'"]?)javascript:/i', ' $1="$2#"', $html)
关键点:
- 开头
\s+匹配任意空白,防属性前空格/换行 -
on\w+覆盖所有事件名(onload、onmouseover等) -
[\'"]?允许无引号或单/双引号,避免漏匹配 - 结尾加
i修饰符,忽略大小写
HTMLPurifier 是唯一能兼顾标签 + 属性 + 嵌套结构的方案
手写正则或组合 strip_tags() + preg_replace() 很难覆盖所有 XSS 绕过手法(比如 SVG 标签、CSS expression、data: 协议、Unicode 编码混淆)。真正需要保留富文本时,HTMLPurifier 是目前 PHP 生态里唯一经过长期实战检验的白名单过滤器。
配置要点:
- 禁用
HTML.AllowedElements,改用HTML.Allowed指定允许的标签+属性组合 - 显式关闭危险协议:
$config->set('URI.DisableExternalResources', true) - 对
<a></a>限制href只能是http、https、#或mailto: - 启用
Attr.EnableID仅当真需要锚点跳转时才开,否则默认关
输出位置决定转义方式,不是输入阶段统一过滤
很多人误以为“入库前过滤一次就万事大吉”,但 XSS 是输出上下文问题。同一个字符串,在 HTML 文本中要用 htmlspecialchars(),在 <input value="..."> 中也要用它,但在 <script>var x = "...";</script> 中必须用 json_encode(..., JSON_HEX_TAG | JSON_HEX_AMP)。
所以:哪怕你用 HTMLPurifier 存了干净 HTML,渲染到 JS 字符串里时仍要换函数,否则 会提前闭合标签。
最易被忽略的是 CSS 内联样式 —— style="color: <?php echo $user_color; ?>",这里不能用 htmlspecialchars(),而应正则校验是否为合法颜色值(如 /^#([0-9A-F]{3}){1,2}$/i),否则攻击者可注入 expression(alert(1))(IE 旧版)或 url(javascript:...)。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











