Laravel项目中最可能出SQL注入的地方是绕过框架安全机制的三类代码:whereRaw()等Raw方法、拼接用户输入的列名/表名、未用?占位符的DB::statement()或DB::select()。

直接看哪里用了 raw 表达式和动态标识符
Laravel 项目里最可能出 SQL 注入的地方,不是 where() 这类标准方法,而是你主动绕过框架安全机制的地方。重点盯三类代码:所有带 Raw 后缀的方法(whereRaw()、selectRaw()、orderByRaw())、拼接用户输入进列名/表名的字符串(比如 "product_variant_{$request->input('id')}"),以及 DB::statement() 或 DB::select() 中没用 ? 占位符的地方。
这些位置不会被 Laravel 自动转义——PDO 预处理只保护参数值,不保护 SQL 结构本身。哪怕你只拼了一个数字进去,只要没做白名单校验,就可能被构造为 1, (SELECT password FROM users) 这种字段列表。
- 搜索整个项目:
grep -r "whereRaw\|selectRaw\|orderByRaw\|havingRaw" app/ - 再搜字符串拼接:
grep -r "\$request->.*->.*input\|->input.*\$" app/ | grep -E "select\(|->select\(|->table\(|DB::" - 特别注意路由参数或 JSON 字段里传来的排序字段:
order_by=created_at; DROP TABLE users--这种在orderByRaw()里直接拼就炸了
检查请求验证是否覆盖了所有动态标识符输入
很多开发者以为加了 $request->validate(['id' => 'required|integer']) 就万事大吉,但整型校验挡不住 id=1%0AUNION%20SELECT%20version() 这种 URL 编码绕过,更挡不住字段名这种非数值上下文。真正有效的防护是白名单约束,不是类型过滤。
比如用户传 variant_id=2,你要查 product_variant_2 字段,那就必须写死允许值:'variant_id' => 'required|integer|in:1,2,3'。如果允许值会变,就用映射数组代替拼接:$columns = [1 => 'product_variant_1', 2 => 'product_variant_2']; $column = $columns[$var] ?? abort(400);
- 别信
in_array($id, range(1, 100))—— 范围太大等于没限制 - 别用正则匹配字段名前缀,比如
preg_match('/^product_variant_\d+$/', $input)—— 攻击者可以填product_variant_1 FROM users -- - 所有用于
orderBy()的字段名,必须从预定义数组里取,不能直接用$request->input('sort')
用日志和错误回显快速暴露问题点
打开 Laravel 的 APP_DEBUG=true 和数据库慢查询日志,然后对可疑接口发几个试探性请求。典型触发行为包括:返回数据库原始错误(如 SQLSTATE[42S22]: Column not found)、响应时间异常延长(SLEEP(5) 类 payload)、或返回意外多的数据行(UNION SELECT 成功)。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
重点测试场景:
- GET 参数:在 URL 里把
id=1换成id=1'、id=1 OR 1=1、id=1) UNION SELECT 1,2,3-- - JSON POST:把
{"sort": "name"}改成{"sort": "name; DROP TABLE products--"} - 排序字段:
?sort=name&direction=asc→?sort=name&direction=asc,(SELECT password FROM users)
只要某次请求让数据库报错或返回逻辑异常结果,对应代码就该立刻审查。
别依赖 SQLMap 直接扫 Laravel 路由
SQLMap 对 Laravel 默认路由常扫不准,因为中间件、CSRF token、JSON 格式、路由模型绑定都会干扰 payload 注入路径。它更适合扫裸 PHP 接口或未加验证的 API 端点。
真要用,得先确认目标接口是否跳过认证、是否接受 GET 参数(很多 Laravel API 只认 JSON body)、是否关闭了 APP_DEBUG(否则错误信息直接暴露结构)。更靠谱的做法是:人工构造 payload + 查看日志 + 审计对应控制器代码,三者结合比工具盲扫快得多。
最容易被忽略的是:即使所有 where() 都安全,只要有一处 ->orderByRaw($request->input('sort')) 没校验,整个查询就失守。动态标识符的防护粒度必须到字段级,不是接口级。

















