ThinkPHP模板变量输出不自动转义,需手动htmlspecialchars;富文本用HtmlPurifier白名单过滤;禁用{php}标签和fetch()动态加载;ThinkCMF需严控templateFile/content参数并禁写日志目录。

模板变量输出不自动转义,必须手动 htmlspecialchars
ThinkPHP 模板引擎的 {$name} 语法默认不做任何 HTML 转义,攻击者传 <script>alert(1)</script>,页面就直接执行。这不是漏洞,是设计如此——框架把上下文安全责任交还给开发者。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 所有用户输入变量输出到 HTML 上下文,必须显式包裹
htmlspecialchars():{:htmlspecialchars($name, ENT_QUOTES, 'UTF-8')} - 避免依赖全局
default_filter,它对所有变量一视同仁,可能把合法 JSON 字段里的双引号也转义,导致前端解析失败 - 控制器赋值时统一过滤更可控:
$this->assign('title', htmlspecialchars($input['title'] ?? '', ENT_QUOTES, 'UTF-8'))
富文本字段不能用 htmlspecialchars,得上 htmlpurifier 白名单
htmlspecialchars() 会把 <p><strong>Hello</strong></p> 变成纯文本,破坏格式;但放行 <script> 或 onerror= 又等于开门揖盗。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 引入
htmlpurifier库,配置严格白名单:$config->set('HTML.Allowed', 'p,strong,ul,ol,li,a[href|title],img[src|alt]') - 禁用正则删
<script>——正则无法应对注释绕过、<scr<!-->ipt>等变体 - 前端编辑器(如 Tiptap)开启 XSS 过滤只是辅助,服务端校验才是最后一道防线
禁用 {php} 标签,警惕 fetch() 动态模板加载
{php}phpinfo(){/php} 这类语法在 ThinkPHP 模板中默认仍可启用,一旦被探测到,就可能演变为 RCE。更危险的是 fetch() 方法:它会把用户可控的 $content 编译为 PHP 文件并执行,而 display() 只渲染不执行。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 在配置中关闭
{php}标签:'tpl_cache' => false+ 删除模板目录下所有.php缓存文件 - 绝对禁止将用户输入传入
fetch()的$templateFile或$content参数,尤其要防路径遍历(如../../../runtime/logs/test) - 若业务必须动态加载模板,改用白名单硬编码:
$allow_templates = ['article', 'product']; $tpl = in_array(input('tpl'), $allow_templates) ? input('tpl') : 'default';
ThinkCMF 场景下,templateFile 和 content 是高危入口
ThinkCMF 基于 ThinkPHP,但其 fetch() 实现未过滤 $templateFile 和 $content,攻击者可构造 POST /index.php?a=display&templateFile=../runtime/logs/test&content=<%php phpinfo();%>,写入恶意缓存并触发 RCE。
实操建议:
立即学习“PHP免费学习笔记(深入)”;
- 检查所有调用
fetch()的地方,确认参数来源是否完全可控、是否经过白名单校验 - 运行时禁用模板缓存写入权限:
chmod -w runtime/template,或把模板目录移出 Web 可访问路径 - 日志目录不可写——这是攻击者最喜欢利用的“临时落盘”位置,务必从部署层面切断
真正难防的不是单个函数调用,而是变量流转过程中上下文的丢失:一个 input('content') 在控制器里被当成普通字符串,在模型里被当成 SQL 条件,在模板里又被当成 HTML 渲染——每个环节的安全处理必须独立判断,不能指望某一处“过滤了就万事大吉”。
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/shoujipingce/124000.html