ThinkPHP防XSS核心是按上下文精准转义:HTML内容用默认{$var}转义,属性值需控制器中htmlspecialchars处理并加引号,JS内联必须json_encode后|raw输出,富文本须用HTMLPurifier白名单净化。

ThinkPHP模板输出用户内容时防XSS,核心不是“堵住所有输入”,而是确保每个输出位置都按上下文做正确转义。TP5.1默认对{$var}做htmlentities()转义,看似安全,但一旦用|raw、拼JS、填属性值或渲染富文本,就立刻失效——漏洞往往出在这些“例外”场景。
普通HTML内容输出:靠默认转义,但别乱加|raw
TP5.1模板中{$user.content}会自动调用htmlentities()(等效于htmlspecialchars($str, ENT_QUOTES)),能防绝大多数反射型和存储型XSS。前提是:不主动加|raw,也不用{:}直接echo原始变量。
- ✅ 安全写法:
{$item.title}、{$info.desc} - ❌ 危险写法:
{$content|raw}、{:htmlspecialchars_decode($content)}、{:$content} - ⚠️ 注意:如果内容含合法HTML(如后台编辑的图文),不能依赖默认转义,需走富文本专用方案
HTML属性值里输出:必须包裹引号 + 手动转义
像title="{$title}"或data-id="{$id}"这类写法,仅靠模板默认转义不够——若$title含" onclick=alert(1),双引号一闭合,后面就变成可执行脚本。
- ✅ 正确做法:统一用双引号包裹属性,并对变量额外用
htmlspecialchars(TP5.1不支持|html简写,需在控制器中处理):$this->assign('title', htmlspecialchars($input, ENT_QUOTES | ENT_HTML5, 'UTF-8'));
模板中:title="{$title}" - ❌ 避免:
title={$title}(无引号)、value={$val}(属性值未闭合)
JavaScript内联代码中输出:禁用htmlspecialchars,改用json_encode
把用户数据塞进<script>var data = "{$user_input}";</script>是高危操作。此时htmlspecialchars会破坏JSON结构,而不用它又极易被闭合引号+注入。
立即学习“PHP免费学习笔记(深入)”;
- ✅ 唯一安全方式:在控制器中用
json_encode($data, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_QUOT)编码,再assign给模板;
模板中:<script>var data = {$json_data|raw};</script>(|raw此处必要,因json_encode已保证安全) - ❌ 绝对禁止:
<script>var name = "{$name}";</script>或{:$name}
富文本内容输出:不用转义,用HTMLPurifier白名单净化
用户发帖、后台编辑器提交的内容含<p><img><a>等标签,htmlspecialchars会把整个页面变“源码”。这时必须用专业工具清洗,而非绕过转义。
- ✅ 步骤:用Composer安装
ezyang/htmlpurifier,配置只允许安全标签和属性,例如:HTML.Allowed = p,b,i,a[href|title],img[src|alt|width|height]Core.RemoveScriptContents = true(自动剥离<script>及onerror等事件) - ✅ 在控制器或模型中调用:
remove_xss($content)(该函数返回净化后HTML),再assign到模板,最后{$cleaned|raw}输出 - ❌ 禁止:
{$content|raw}直出、或用简单正则删<script>(极易被大小写/注释/编码绕过)



















