thinkphp如何禁用不必要的函数_php危险函数安全加固

为什么 disable_functions 对 ThinkPHP 几乎无效

ThinkPHP 本身不依赖 exec、system、shell_exec 这类函数运行,禁用它们不会影响框架功能,但也不能真正防住利用——因为攻击者常通过反序列化、模板渲染或路由解析等路径绕过函数级限制。真正的风险点不在“用了什么函数”,而在“谁控制了函数的参数”。

disable_functions 只拦截 PHP 内置函数调用,对 eval()、assert()(在 PHP 7.2+ 默认启用)或动态类加载完全无感ThinkPHP 5.1+ 默认开启模板引擎编译缓存,若攻击者能写入 runtime/view/ 目录,可直接植入恶意 PHP 代码,绕过所有函数禁用常见误操作:在 php.ini 中禁用 file_put_contents,结果导致 ThinkPHP 日志写入失败、缓存无法生成,反而暴露错误路径

ThinkPHP 模板层才是高危入口,不是 system()

ThinkPHP 的 think\template\driver\File 和 {:function()} 语法允许在模板中执行任意 PHP 表达式,一旦模板内容可控(如用户提交的页面标题、富文本字段未过滤就进模板),eval 就在后台静默触发。

危险写法示例:{:system(‘id’)} 或 {:call_user_func(‘phpinfo’)} —— 只要模板被用户间接影响,就可能执行ThinkPHP 6.x 默认关闭模板引擎的 tpl_deny_func 配置,需手动在 config/template.php 中显式添加:’tpl_deny_func’ => [‘exec’,’shell_exec’,’system’,’passthru’,’popen’,’proc_open’]更稳妥做法:禁用模板中的函数调用语法,把 ‘tpl_begin’ => ‘{‘ 改成非 PHP 兼容符号(如 ‘tpl_begin’ => ‘{@’),并确保所有模板变量都经 htmlspecialchars 输出

Runtime 目录权限比禁用函数更重要

ThinkPHP 的 runtime/ 目录是运行时缓存、日志、模板编译的落盘位置。如果 Web 进程(如 www-data)对该目录有写+执行权限,攻击者上传一句话木马后,只需触发一次模板编译,就能让恶意代码落地为可访问的 PHP 文件。

典型错误配置:chmod -R 777 runtime/ —— 这等于给攻击者配了把万能钥匙正确权限(Linux):chown -R www-data:www-data runtime/ && chmod -R 755 runtime/ && find runtime/ -type f -exec chmod 644 {} \;额外加固:在 Nginx/Apache 配置中禁止直接访问 runtime/ 下的 PHP 文件,例如 Nginx 中加 location ~ ^/runtime/.*\.php$ { return 403; }

别碰 assert() 和 call_user_func_array() 的参数

ThinkPHP 路由调度、中间件执行、Hook 回调大量使用 call_user_func_array;而部分老版本扩展(如某些验证码、支付 SDK)会用 assert($str) 动态执行字符串。这两处若参数来自用户输入,禁多少函数都没用。

立即学习“PHP免费学习笔记(深入)”;

检查项目中所有 assert( 调用,确保参数是硬编码字符串或经过白名单校验的常量,绝不能是 $_GET[‘x’] 或数据库读取的字段排查 think\Container::invokeMethod、think\facade\Route::miss 等调用链,确认回调方法名是否被用户控制(比如 URL 中传 ?callback=system)PHP 8.1+ 已废弃 assert() 的字符串执行模式,升级 PHP 版本是最省事的加固方式之一

真正卡住攻击链的地方,从来不是“哪个函数被禁了”,而是“哪个变量没过滤”和“哪个目录多给了执行权”。ThinkPHP 的安全水位,取决于你对输入边界的把控,而不是 php.ini 里那一行 disable_functions。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。