PHP框架中定位SQL注入需先识别框架类型及数据库配置,再通过HTTP请求映射控制器,逆向追踪参数是否经whereRaw等绕过预处理的查询方法拼接,最后验证原生SQL执行点并构造Payload测试。

在PHP框架项目中定位SQL注入漏洞,不能只靠全局搜select或mysql_query,因为现代框架普遍封装了数据库操作层,原始函数被隐藏,必须顺着框架的查询构造逻辑逆向追踪可控参数的落地路径。
确认框架类型与数据库驱动入口
打开项目根目录下的composer.json,查看require字段中是否含laravel/framework、thinkphp/think或codeigniter4/framework等关键词;若无明确框架名,则检查index.php是否包含new ThinkPHP\、Illuminate\Foundation\Application或CodeIgniter\CodeIgniter类实例化语句。
找到入口后,立即定位数据库配置文件:Laravel查config/database.php或.env中的DB_DRIVER,ThinkPHP看config/database.php里的'type' => 'mysql',CodeIgniter 4则检查app/Config/Database.php。这一步必须做,【不同框架的SQL拼接机制完全不同,跳过此步直接搜SQL关键字90%会漏掉真实注入点】。
抓取HTTP请求并映射到控制器方法
用Burp Suite拦截一个带参数的GET请求,例如/user/profile?id=123,观察响应体是否含用户数据;再改写为/user/profile?id=123%27,若页面报错且错误信息含SQL syntax或MySQL字样,说明该参数已进入SQL执行环节。
立即学习“PHP免费学习笔记(深入)”;
根据路由规则反推控制器:Laravel中Route::get('/user/profile', [ProfileController::class, 'show']) → 找到app/Http/Controllers/ProfileController.php;ThinkPHP中route::get('user/profile','user.Profile/show') → 对应app/controller/user/Profile.php;CodeIgniter 4则查app/Controllers/User.php里的public function profile()方法。
逆向追踪参数如何进入查询构造器
第一步:在控制器方法中找到接收参数的代码,常见形式有$id = $this->request->get('id')(CI4)、$id = request('id')(Laravel)、$id = input('get.id')(ThinkPHP)。
第二步:跟踪变量后续调用链,重点识别是否经过where()、find()、select()等查询构造方法。例如Laravel中User::where('id', $id)->first()是安全的,但DB::select("SELECT * FROM users WHERE id = $id")或User::whereRaw("id = $id")->first()就是高危点。
第三步:若发现whereRaw、DB::unprepared、query->execute(ThinkPHP)、$builder->setQuery(CI4)等绕过参数绑定的调用,立刻停住——这些是框架层主动放弃预处理的明确信号,【只要变量未经intval()、(int)强制转换或正则校验就直接拼入,即构成可利用注入】。
验证框架是否启用全局过滤或中间件拦截
方法一:搜索项目中是否存在app/Http/Middleware/目录下的SqlInjectionFilter.php或类似名称中间件,打开后检查是否对$_GET、$_POST做strip_tags、htmlspecialchars或正则替换单引号/分号。
方法二:在app/Providers/AppServiceProvider.php(Laravel)或app/common.php(ThinkPHP)中查找str_replace(["'", '"', ';'], '', $input)类全局清洗逻辑;若存在,需测试清洗是否在参数进入查询前生效——把清洗逻辑注释掉再复现请求,对比结果变化。
方法三:直接查看框架文档确认默认行为:Laravel 9+默认所有where()使用PDO预处理,但whereRaw()不自动绑定;ThinkPHP 6.0+对where()参数默认转义,但whereLike()若第二个参数为变量且未加%通配符包裹,仍可能被绕过。
定位原生SQL执行点并构造Payload
第一步:用VS Code全局搜索->execute()、->query(、DB::select(、Db::name(、$db->query(等关键词,勾选“正则”模式,输入(->execute\(|DB::select\(|Db::name\(.*?-\>select|$db->query\()。
第二步:对每个匹配结果,检查括号内是否含未加引号的变量拼接,例如"SELECT * FROM user WHERE status = " . $status或"id = " . input('id');特别注意字符串连接符.和printf、sprintf格式化函数的使用场景。
第三步:对确认的拼接点,构造最小化Payload验证:先试1 and 1=1与1 and 1=2观察响应差异;再用1 union select 1,2,3测列数;最后用1 and extractvalue(1,concat(0x7e,(select database()),0x7e))提取库名。所有测试必须在关闭错误回显的生产环境用盲注方式推进,避免触发WAF拦截。



















