ThinkPHP模型修改器_自动过滤XSS攻击的HTML内容【指南】

雨芳小哥_2256

雨芳小哥_2256

2026-05-10

461人浏览

原创

thinkphp模型的$filter属性对xss过滤基本没用,因其仅在data()->validate()->save()链式调用且显式启用时触发,而save(['field'=>$raw])等写法直接绕过;真正可靠入口是before_write事件配合htmlpurifier单例处理富文本、htmlspecialchars按字段类型精准转义。

thinkphp模型修改器_自动过滤xss攻击的html内容【指南】

ThinkPHP模型的$fillter属性为什么对XSS过滤基本没用

因为$filter在TP6中仅在data()->validate()->save()链式调用且显式启用时才触发,而save(['field' => $raw])这种写法直接绕过它。你设了protected $filter = ['content' => 'htmlspecialchars'],但只要控制器里写了$model->save(['content' => '<script>alert(1)</script>']),恶意脚本就直入库。

常见错误现象包括:后台编辑器提交的富文本被htmlspecialchars()双转义成源码、toWrite()被误以为能改数据值(其实只映射字段名)、before_write事件没注册或函数签名不对导致不执行。

  • $filter只作用于data()传入的数据,不处理关联保存、Db::table()->insert()、批量更新等场景
  • 过滤函数执行时机在验证之后、写入之前,但仅限字段级,无法递归处理JSON字段或嵌套数组
  • 若字段本身已含HTML实体(如数据库里存的是<script></script>),再套一次htmlspecialchars()会变成<script>,前端显示异常

真正生效的XSS过滤入口是before_write事件

这是TP6中唯一稳定、可控、可覆盖所有save()路径的过滤点。必须在模型boot()方法中显式绑定,且sanitizeFields()需手动遍历并区分字段类型——不能无差别调用htmlspecialchars()。

使用场景:纯文本字段(如title、desc)需要转义;富文本字段(如content)必须跳过,否则破坏排版;JSON字段(如config)要先json_decode()再递归处理字符串值,最后json_encode()回写。

  • 注册方式:self::event('before_write', [self::class, 'sanitizeFields']);
  • 在sanitizeFields()中用array_walk_recursive()扫描值,对is_string($val) && !preg_match('/^的字段才调用<code>htmlspecialchars($val, ENT_QUOTES | ENT_HTML5, 'UTF-8')
  • 避免重复转义:检查字符串是否已含<、>等实体,有则跳过

富文本字段必须用HTMLPurifier白名单清洗,不能靠htmlspecialchars

htmlspecialchars()会让<p>Hello</p><div class="aritcle_card flexRow artxards"> <div class="artcardd flexRow"> <a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill6712" title="Wechat HTML Publisher"><img src="https://img.php.cn/upload/skill/000/000/081/179109368394970.jpg" alt="Wechat HTML Publisher" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a> <div class="aritcle_card_info flexColumn"> <a rel="nofollow" href="/xiazai/skill6712" title="Wechat HTML Publisher" class="overflowclass">Wechat HTML Publisher</a> <p class="overflowclass">直接上传HTML富文本到微信公众号草稿箱。支持完整的HTML格式,无需Markdown转换。</p> </div> <a rel="nofollow" href="/xiazai/skill6712" title="Wechat HTML Publisher" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a> </div> </div>变成纯文本,而用户真正需要的是渲染后的段落。XSS防护的关键不是“不让HTML出现”,而是“只允许安全的HTML”。这时候HTMLPurifier是唯一靠谱的选择。

注意:不要在app/common.php里new HTMLPurifier(),这会导致每次调用都重新编译规则,性能暴跌。必须通过容器单例注册。

  • 注册单例位置:app\common\provider\AppServiceProvider.php中的register()方法
  • 绑定方式:app()->bind('HtmlPurifier', function () { return new \HTMLPurifier(\HTMLPurifier_Config::createDefault()); });
  • 白名单配置示例:$config->set('HTML.Allowed', 'p,b,i,a[href|title],img[src|alt|width|height]');,禁用on*事件和javascript:协议
  • 调用时机:在before_write中识别出富文本字段后,用app('HtmlPurifier')->purify($value)处理

别在中间件或控制器里提前过滤input()数据

有人习惯在中间件里对$_POST全量调用htmlspecialchars(),结果导致API返回的JSON里全是<,前端解析失败;或者控制器里$data = input(); array_walk($data, 'htmlspecialchars');,后续想把$data['title']塞进<meta name="description" content="...">时,双引号没被ENT_QUOTES保护,被空格截断后注入onclick。

真正该过滤的地方只有两个:入库前(按字段类型选htmlspecialchars或HTMLPurifier)、输出时(按上下文选htmlspecialchars、json_encode或HTMLPurifier)。中间件只适合处理明确用于HTML展示的键(如['title', 'nickname']),且不能修改$request对象本身。

  • 禁止在中间件里遍历$_REQUEST做全局过滤,TP6的Request是只读快照,强行改会引发不可预测行为
  • input('name', '', 'htmlspecialchars')仅限纯文本展示场景,且第三参数必须传全:input('name', '', 'htmlspecialchars,ENT_QUOTES,UTF-8')
  • 模板里{$content|htmlspecialchars}默认不带ENT_QUOTES,等价于htmlspecialchars($content, ENT_COMPAT),单引号漏转——务必用{:htmlspecialchars($content, ENT_QUOTES | ENT_HTML5, 'UTF-8')}

最易被忽略的点是:富文本字段入库前必须走HTMLPurifier,但它的配置必须单例化;before_write事件里处理JSON字段时,要先解码再递归过滤字符串,否则array_walk_recursive()对JSON字符串无效;所有htmlspecialchars()调用必须显式传ENT_QUOTES和'UTF-8',缺一不可。

php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!

相关文章

HTML速学教程(入门课程)
HTML速学教程(入门课程)

HTML怎么学习?HTML怎么入门?HTML在哪学?HTML怎么学才快?不用担心,这里为大家提供了HTML速学教程(入门课程),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

php thinkphp html 修改器

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

2023.09.01

10004

6

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

5941

5

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

2075

5

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

2023.10.23

3728

4

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

2023.10.23

4414

6

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.03

3471

9

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.09

4937

8

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.13

3862

8

sprintf函数用法详解
sprintf函数用法详解

sprintf函数的用法:1、格式化字符串;2、指定输出宽度和精度;3、返回值。更多关于sprintf函数用法详解的内容,大家可以阅读下面的文章。

2023.11.27

11842

4

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
墨刀帮助中心
墨刀帮助中心

共0课时 | 0人学习

MyEclipse学习中心
MyEclipse学习中心

共0课时 | 0人学习

Apache Subversion 官方手册
Apache Subversion 官方手册

共0课时 | 0人学习