ThinkPHP默认不防护XSS,需开发者主动过滤;模板{$var}不自动转义,必须显式用{$var|html};富文本需HTMLPurifier白名单清洗;输入层应在全局中间件净化;须设HttpOnly/Secure Cookie、CSP头及JSON安全响应。

ThinkPHP 本身不默认过滤 XSS,所有用户输入和输出都需开发者主动防护。靠“开个配置就安全”会直接导致漏洞,尤其在 TP5.1、TP6 和 TP8 中,default_filter 已失效或被移除,模板变量 {$var} 不自动转义,input() 返回原始数据——这意味着攻击者提交 <script>alert(1)</script>,它就会原样执行。
模板输出必须显式转义
这是最常见也最容易忽略的一环。TP5.1/6/8 均取消了模板自动转义,{$var} 等价于 <?php echo $var; ?>,毫无防护。
- 普通文本输出一律用
{$var|html},它调用htmlspecialchars($var, ENT_QUOTES, 'UTF-8'),能防绝大多数反射型和存储型 XSS - 禁止混用过滤器顺序,例如
{$var|default='-'|html}是错的:默认值-没经过html处理,可能被利用 - 富文本内容(如 TinyMCE 编辑器提交)不能走
|html,否则会破坏标签。应先在控制器或模型中用remove_xss()清洗,模板中用{:htmlspecialchars_decode($safe_html)}安全输出 - 检查
template.default_filter配置是否仍为'htmlspecialchars',避免被覆盖为空字符串或简写'h'
输入层要按需清洗,不能只靠一次过滤
仅在控制器某处调用 HTMLPurifier::clean() 是危险的——因为 input('content')、param('content')、验证器、日志记录等环节仍会反复读取原始未过滤参数。
- TP6 推荐在全局中间件中处理:用
$request->get()和$request->post()获取原始数据,清洗后调用$request->mergeParam($cleaned)合并进 Request 对象,确保后续所有input()调用都返回已净化值 - TP5.1 的
default_filter只对未指定第三参数的I()或input()生效,且必须写全:'default_filter' => "htmlspecialchars, ENT_QUOTES, 'UTF-8'",漏掉ENT_QUOTES会导致单引号绕过(如onerror='alert(1)') - 不要修改
$_GET/$_POST全局变量,TP6+ 已脱离超全局依赖,改了无效
HTMLPurifier 必须严格白名单配置
HTMLPurifier 不是“装上就安全”的黑盒。开箱即用的配置过于保守(如默认禁掉 <img>),而 createDefault() 又过于宽松,极易被绕过。
立即学习“PHP免费学习笔记(深入)”;
- 禁止使用
HTMLPurifier_Config::createDefault();必须显式设置白名单:$cfg->set('HTML.Allowed', 'p,b,i,strong,a[href|title],img[src|alt|width|height]'); - 强制关闭 JS 执行能力:
$cfg->set('Core.RemoveScriptContents', true);、$cfg->set('HTML.SafeIframe', false); - 限制协议类型:
$cfg->set('URI.AllowedSchemes', ['http', 'https', 'mailto']);,排除javascript:和data: - 禁用所有事件属性:
$cfg->set('HTML.Attr.EnableID', false);,并确保不放行on*类属性(如onclick、onload)
其他关键防线不能缺位
XSS 防护是分层的,单点加固远远不够。
- 敏感 Cookie 必须设
HttpOnly和Secure标志,防止 JS 读取 session 或自动登录凭证 - 启用 CSP(Content Security Policy)头,例如
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline',配合 nonce 使用可进一步限制内联脚本 - 避免在 JS 中拼接用户数据,如
document.write(input)、eval()、innerHTML = input;确需动态渲染,优先用textContent或 DOM API - JSON 接口也要防 XSS:响应头加
X-Content-Type-Options: nosniff,前端用JSON.parse()而非eval(),服务端返回前对字段做htmlspecialchars(若 JSON 内容最终会插入 HTML)



















