ThinkPHP 漏洞(下)

一、紧急临时修复(未升级前先用,止损优先)

适用于无法立即升级框架版本的场景,核心是拦截危险请求、过滤敏感参数、禁用高危功能

1. 入口文件加固(public/index.php)

define('APP_PATH', __DIR__ . '/../app/');之后添加以下代码,拦截 RCE/SQL 注入的核心攻击参数:

php 复制代码
<?php
// 1. 禁用危险函数调用(按需添加)
if (!function_exists('disable_danger_functions')) {
    function disable_danger_functions() {
        $danger_functions = ['eval', 'system', 'exec', 'passthru', 'shell_exec', 'proc_open', 'popen'];
        foreach ($danger_functions as $func) {
            if (function_exists($func)) {
                rename_function($func, '_' . $func); // 重命名危险函数(需安装runkit扩展)
            }
        }
    }
    // 仅生产环境启用
    if (env('app_debug') === false) {
        disable_danger_functions();
    }
}

// 2. 过滤危险请求参数
$danger_params = [
    's', '_method', 'function', 'vars', 'filter', 'order', 'group', 'having',
    '\\think\\', 'call_user_func', 'call_user_func_array'
];
// 检查GET/POST/COOKIE参数
$request_data = array_merge($_GET, $_POST, $_COOKIE);
foreach ($request_data as $key => $value) {
    if (in_array($key, $danger_params) || is_string($value) && strpos($value, '\\think\\') !== false) {
        http_response_code(403);
        die('Illegal Request: ' . $key);
    }
}

// 3. 限制请求方法(仅允许必要的)
$allow_methods = ['GET', 'POST', 'PUT', 'DELETE'];
if (!in_array($_SERVER['REQUEST_METHOD'], $allow_methods)) {
    http_response_code(405);
    die('Method Not Allowed');
}
?>

2. 禁用自动路由与调试模式

修改config/app.php,关闭高风险默认配置:

php 复制代码
return [
    // 禁用自动路由(防止未授权访问)
    'auto_route' => false,
    // 生产环境必须关闭调试模式(防止信息泄露)
    'app_debug' => false,
    'app_trace' => false,
    // 禁用远程调试
    'remote_debug' => false,
    // 限制日志级别(不输出敏感信息)
    'log_level' => ['error', 'warning'],
];

3. Nginx/Apache 层面拦截

在 Web 服务器配置中添加规则,拦截恶意请求:

nginx

复制代码
# Nginx配置(nginx.conf / 站点配置)
server {
    # 拦截包含ThinkPHP RCE特征的请求
    if ($request_uri ~* "(\\/think\\/|call_user_func|eval\\(|system\\(|exec\\()") {
        return 403;
    }
    # 拦截SQL注入关键词
    if ($request_uri ~* "(union select|insert into|update |delete from|drop table|-- |#)") {
        return 403;
    }
    # 禁止访问敏感目录
    location ~ ^/(runtime|config|vendor|.git)/ {
        deny all;
    }
    # 禁止访问PHP配置文件
    location ~ \.(php|php5|php7)$ {
        try_files $uri =404;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

二、版本根治修复(唯一彻底解决漏洞的方式)

不同版本的升级路径明确,优先升级到对应分支的最新稳定版:

ThinkPHP 版本 存在漏洞版本范围 升级目标版本 升级注意事项
3.2.x 全版本 建议直接升级到 6.x 3.2.x 已停止维护,无安全更新,需重构部分代码(如控制器、模型写法)
5.0.x 5.0.0-5.0.23 5.0.24+ 仅需替换框架核心文件(thinkphp / 目录),代码兼容度 99%
5.1.x 5.1.0-5.1.37 5.1.38+ / 6.1.x 5.1.x 升级到 6.x 需适配命名空间、中间件写法
6.0.x 6.0.0-6.0.12 6.0.13+ / 6.1.x 6.x 升级仅需执行composer update topthink/framework
8.0.x 8.0.0-8.0.x(如有漏洞) 8.0.x 最新稳定版 8.x 为最新分支,通过 composer 自动更新即可

升级操作步骤(以 6.x 为例):

复制代码
# 1. 备份项目代码和数据库
# 2. 进入项目根目录,执行composer升级
composer update topthink/framework --no-dev
# 3. 清理缓存
php think clear
# 4. 验证升级成功
php think version

三、分类型漏洞专项修复

针对不同类型的漏洞,给出精准的修复代码和配置:

1. RCE 漏洞修复(核心)

  • 根本:升级框架版本;

  • 代码层面 :禁止直接调用危险函数,统一使用框架封装的方法:

    php 复制代码
    // 错误:直接使用call_user_func
    call_user_func($_GET['func'], $_GET['param']);
    // 正确:白名单限制可调用函数
    $allow_functions = ['getUser', 'getOrder', 'getGoods'];
    $func = input('get.func/s');
    if (in_array($func, $allow_functions) && function_exists($func)) {
        $func(input('get.param/d'));
    }

2. SQL 注入漏洞修复

核心原则:所有 SQL 操作必须使用参数绑定,禁止手动拼接

php 复制代码
// 错误写法(拼接变量)
$id = input('get.id');
$user = Db::table('user')->where("id = $id")->find();

// 正确写法1:数组条件
$user = Db::table('user')->where(['id' => $id])->find();

// 正确写法2:占位符绑定
$user = Db::table('user')->where("id = :id", ['id' => $id])->find();

// 针对order/group注入:白名单限制
$allow_sort = ['id', 'name', 'create_time'];
$sort = input('get.sort/s', 'id');
$sort = in_array($sort, $allow_sort) ? $sort : 'id';
$list = Db::table('goods')->order($sort)->select();

3. 任意文件操作修复

(1)文件读取 / 下载
php 复制代码
// 错误:直接使用用户传入的文件路径
$file = input('get.file');
return download($file);

// 正确:白名单+真实路径校验
$allow_files = [
    realpath(ROOT_PATH . 'public/static/download/guide.pdf'),
    realpath(ROOT_PATH . 'public/static/download/readme.txt')
];
$file = realpath(input('get.file')); // 解析真实路径,防止../遍历
if (!in_array($file, $allow_files) || strpos($file, ROOT_PATH) === false) {
    die('Illegal File');
}
return download($file);
(2)文件上传
php 复制代码
// 上传验证:后缀+MIME+内容三重校验
$file = request()->file('upload');
// 1. 后缀白名单
$validate = new \think\file\Validate([
    'ext' => 'jpg,png,pdf', // 仅允许这些后缀
    'size' => 1024*1024*2, // 限制2MB
]);
if (!$file->validate($validate)->check()) {
    return json(['code' => 0, 'msg' => $file->getError()]);
}
// 2. MIME类型校验
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $file->getRealPath());
$allow_mime = ['image/jpeg', 'image/png', 'application/pdf'];
if (!in_array($mime, $allow_mime)) {
    return json(['code' => 0, 'msg' => '文件类型非法']);
}
// 3. 重命名文件,防止覆盖
$save_name = \think\facade\Filesystem::disk('public')->putFile('upload', $file, 'md5');

4. 未授权访问 / 权限绕过修复

(1)全局权限中间件(ThinkPHP6+)

创建app/middleware/Auth.php

php 复制代码
<?php
namespace app\middleware;

class Auth
{
    public function handle($request, \Closure $next)
    {
        // 白名单路由(无需登录)
        $white_list = ['/login', '/register', '/api/captcha', '/static/*'];
        $current_path = $request->path();
        
        // 检查白名单
        $is_white = false;
        foreach ($white_list as $white) {
            if ($white === $current_path || (strpos($white, '*') !== false && strpos($current_path, rtrim($white, '*')) === 0)) {
                $is_white = true;
                break;
            }
        }
        if ($is_white) {
            return $next($request);
        }
        
        // 检查登录状态
        if (!session('user_id')) {
            // AJAX请求返回JSON,普通请求重定向
            if ($request->isAjax()) {
                return json(['code' => 401, 'msg' => '未登录']);
            } else {
                return redirect('/login');
            }
        }
        
        // 检查角色权限(按需添加)
        $role = session('role');
        $admin_routes = ['/admin/*', '/api/admin/*'];
        if (in_array($role, ['admin']) === false && $this->matchRoute($current_path, $admin_routes)) {
            return json(['code' => 403, 'msg' => '无权限']);
        }
        
        return $next($request);
    }
    
    // 路由匹配辅助方法
    private function matchRoute($path, $routes)
    {
        foreach ($routes as $route) {
            if (strpos($route, '*') !== false && strpos($path, rtrim($route, '*')) === 0) {
                return true;
            } elseif ($route === $path) {
                return true;
            }
        }
        return false;
    }
}

app/middleware.php中注册:

php 复制代码
return [
    \app\middleware\Auth::class, // 全局生效
];
(2)禁用空控制器

修改config/route.php

php 复制代码
return [
    'empty_controller' => '', // 禁用空控制器,防止绕过
    'route_check' => true, // 开启路由校验
];

四、全维度长期加固(生产环境必做)

1. 配置层面

  • 数据库配置加密:使用环境变量 / 配置中心存储数据库账号密码,不直接写在database.php中;

    php 复制代码
    // config/database.php
    return [
        'username' => env('DB_USERNAME', ''),
        'password' => env('DB_PASSWORD', ''),
    ];
  • 禁用函数:在php.ini中配置disable_functions = eval,system,exec,passthru,shell_exec,proc_open,popen

  • 限制 PHP 执行权限:open_basedir = /var/www/your-project/:/tmp/,防止跨目录访问。

2. 代码层面

  • 统一使用input()方法获取参数,指定类型过滤:

    php 复制代码
    $id = input('get.id/d', 0); // 强制转为数字
    $name = input('post.name/s', '', 'trim,htmlspecialchars'); // 过滤HTML字符
  • 日志脱敏:对日志中的密码、Token 等敏感信息进行替换;

  • 避免使用$_GET/$_POST/$_COOKIE全局变量,统一用request()对象。

3. 部署层面

  • 启用 HTTPS,配置 HSTS,防止中间人攻击;
  • 部署 WAF(如阿里云 WAF、宝塔 WAF),拦截 SQL 注入、XSS、RCE 等攻击;
  • 定期备份代码和数据库,防止漏洞被利用后数据丢失;
  • 以非 root 用户运行 PHP-FPM/Nginx,限制文件读写权限。

总结

  1. ThinkPHP 漏洞修复的核心优先级:先升级框架版本(根治)→ 紧急拦截危险请求(止损)→ 分类型修复专项漏洞(精准)→ 全维度加固(长期);
  2. 所有修复的底层逻辑:禁用高危功能 + 白名单校验输入 + 最小权限运行,尤其是禁用调试模式、强制参数绑定、配置全局权限中间件这三点;
  3. 临时修复仅用于应急,长期必须升级到最新稳定版,同时定期扫描依赖漏洞(如使用composer audit)。
相关推荐
前路不黑暗@2 小时前
Java项目:Java脚手架项目的 B 端用户服务(十四)
android·java·开发语言·spring boot·笔记·学习·spring cloud
Rainman博3 小时前
AMS-Activity启动流程
android
恋猫de小郭3 小时前
Flutter 设计包解耦新进展,material_ui 和 cupertino_ui 发布预告
android·前端·flutter
blackorbird6 小时前
新型Keenadu安卓固件级后门揭开跨僵尸网络协同攻击链条
android·网络
前路不黑暗@7 小时前
Java项目:Java脚手架项目的阿里云短信服务集成(十六)
android·java·spring boot·学习·spring cloud·阿里云·maven
吴声子夜歌7 小时前
RxJava——Flowable与背压
android·java·rxjava
L-李俊漩7 小时前
Android studio修改gradle路径
android·android studio
九狼JIULANG8 小时前
基于Flutter+Riverpod+MVI 实现的跨平台「AI 提示词优化工具」
android·开源·github
山北雨夜漫步8 小时前
点评day03优惠卷秒杀-库存超卖,一人一单(单机模式)
android