xss_clean 会误删合法 html 标签,因其仅依赖黑名单正则替换,不解析 dom、无白名单机制,导致代码高亮、markdown 等富文本被破坏;应关闭全局过滤,对富文本改用 htmlpurifier 白名单净化。

xss_clean 会把合法 HTML 当成攻击删掉,别用它处理富文本
为什么 xss_clean 一开就破坏代码高亮和 Markdown 渲染
它不区分「要展示的 HTML」和「危险脚本」,对所有输入统一做正则替换:遇到 <pre class="brush:php;toolbar:false;"></pre>、<code>、<script></script> 甚至 <svg></svg> 都可能被砍掉或属性清空。比如用户提交的 <pre class="brush:php;toolbar:false;"><code class="php">echo "hello";</code></pre>,xss_clean 可能直接干掉 class 属性,或把整个 <code> 标签替换成纯文本。
- CI3 的
xss_clean没有白名单机制,只靠黑名单匹配,<iframe></iframe>、<object></object>、onerror、javascript:等会被无差别拦截 - 它不解析 DOM 结构,所以
<div onclick="alert(1)"> 和 <code><div onclick="alert(1)"> 都会被识别,但 <code><div on>click="alert(1)"> 就可能漏过<li>富文本编辑器(如 TinyMCE、Quill)输出的带样式的 HTML,基本无法通过 <code>xss_clean安全保留 - 关闭全局过滤:
$config['global_xss_filtering'] = FALSE;,避免对所有 POST/GET 做暴力 strip - 对普通字段仍可用
$this->input->post('title', TRUE)—— 这个TRUE是调用xss_clean,只用于纯文本场景(如标题、昵称) - 对富文本字段,改用
HTMLPurifier库,配置白名单:allowedElements设为['p','br','strong','em','code','pre','ol','ul','li','table','tr','td','th'],allowedAttributes仅保留class、style(且 style 要配CSS.AllowTricky为 false) - 别在控制器里直接
echo $content,视图中必须用echo $purifier->purify($content)输出 - 对纯文本输出:
= esc($content, 'html')—— 把变成 <code><,适合评论、简介等不需格式的字段 - 对需保留标签的内容:
= $purifier->purify($content),且必须确保$purifier实例已配置好元素白名单,不能直接传原始字符串给视图 - 千万别混用:
= esc($purifier->purify($content), 'html')是双重转义,<p></p>会变成<p>,页面显示为源码 - CSRF 令牌和输出转义无关,
csrf_field()和esc()各司其职,别指望一个解决所有问题 -
remove_invisible_characters()不防 XSS,只清控制字符,别把它当安全函数塞进输入流程 - 用
htmlspecialchars()手动处理时,记得设ENT_QUOTES | ENT_SUBSTITUTE,否则单引号、无效 UTF-8 可能导致截断 - 前端富文本渲染后,如果还用 JS 动态
innerHTML = ...插入服务端返回的内容,esc()或purify()就白做了 - CI3 升 CI4 时,
$this->input->post('x', TRUE)会报错 —— CI4 没这个参数,得改用$this->request->getPost('x')+ 后续净化
CI3 中保留部分 HTML 的实际做法
想让用户发的代码块、表格、加粗斜体正常显示,又不让 JS 执行,就得绕过 xss_clean,改用结构化清洗。
CI4 中彻底放弃 xss_clean,改用 esc() + 白名单库组合
CI4 已移除 xss_clean,esc() 是默认输出转义函数,但它本身不支持白名单 HTML,只是上下文编码工具。
容易被忽略的关键点
最常出问题的地方不在「用没用过滤」,而在「在哪一层做、对谁做、做了之后还怎么用」。










