thinkphp模板变量默认不转义,{$var}直接输出用户输入会触发xss,因6.0+取消default_filter且设计上要求开发者按上下文显式处理转义。

ThinkPHP 模板变量默认不转义,{$var} 等价于 php echo $var; ?>,直接输出用户输入就是 XSS 入口 —— 必须在模板层按上下文显式处理,不能依赖框架兜底。
为什么 {$var} 直接输出会触发 XSS
ThinkPHP 6.0+ 和 8.0 都取消了 default_filter 配置项,也不再对 {$var} 自动 htmlspecialchars。用户提交 <script>alert(1)</script>,页面就会执行脚本。这不是 bug,是设计选择:框架把转义决策权交还给开发者。
- 常见错误现象:
{$title}渲染含onerror="alert(1)"的字符串,属性被截断后执行 JS - 富文本场景下误用
{$content|html},导致<img>标签被干掉,内容显示异常 - JSON 接口返回未过滤字段,前端用
el.innerHTML = data.content二次触发 XSS
HTML 内容输出必须用 htmlspecialchars 三参数完整调用
仅写 htmlspecialchars($var) 不够安全 —— 缺少 ENT_QUOTES 和 UTF-8 参数时,单引号、中文或 HTML5 实体可能绕过防护。
- 正确写法:
{:htmlspecialchars($var, ENT_QUOTES | ENT_HTML5, 'UTF-8')} - 简写语法
{$var|html}仅在 TP8.0.1+ 可用,但它内部用的是ENT_COMPAT,不转义单引号,onerror仍可利用 - 不要在控制器 assign 前统一过滤:同一变量可能既用于 HTML 文本、又用于
<meta content="...">属性值,提前转义会破坏原始数据
属性值、JS 字符串、富文本要分上下文处理
一个变量插入不同位置,转义方式完全不同。混用会导致漏洞或渲染失败。
- 属性值(如
title="{$title}"):必须确保引号包裹,且内容已用htmlspecialchars处理;若引号缺失,空格会截断属性并注入事件 - JS 字符串内嵌(如
var name = "{$name}";):必须用{:json_encode($name, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP)},不能只靠htmlspecialchars - 富文本(如后台编辑器内容):禁用
htmlspecialchars,改用HTMLPurifier白名单过滤,配置HTML.Allowed严格限定允许标签和属性
|raw 过滤器只能用于已净化的数据
|raw 不是“信任开关”,而是“跳过转义指令”。它不校验内容,只取消框架层面的自动处理。
- 危险写法:
{|$user_input|raw}—— 用户输入直出,等于主动开后门 - 正确顺序:
{|$cleaned_html|raw},其中$cleaned_html已由HTMLPurifier净化过 -
|raw必须位于过滤器链末尾,{|$desc|default='-'|raw}合法,{|$desc|raw|nl2br}中|nl2br会被忽略 - 前端用
innerHTML插入|raw输出的内容前,仍需确认后端已完成上下文敏感过滤
最易被忽略的点:JSON 接口返回的字段,哪怕只用于前端 JS 渲染,也得在后端做 htmlspecialchars 或 json_encode 处理 —— ThinkPHP 的 json() 方法不做任何过滤,它只负责编码。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











