Laravel 的路由参数被注入 HTML 代码,页面展示恶意外链?以 Dcat Admin 为例看我是如何解决!
背景
- 最近上线的项目比较多,而且上线前必须经过几轮漏扫才能符合要求。
- 好难受,这次还是被攻击了,辛辛苦苦做一个项目,却总会被认定为
易受攻击对象
。
- 没办法,做项目和做工程一样,安全第一☝,生产第二!!!
- 话不多说,扶我起来,我还能再坚持一下
…
问题描述
1. 问题还原
- 通过修改路由参数值,就可以注入,你想注入的任何内容。
- 小试牛刀 - 将路由参数的值变为
1'
,页面居然能正常展示,如事发现场一
所示。 - 大刀阔斧 - 将路由参数的值变为长的
HTML
如事发现场二
所示:http://xxxxx.test/admin/merchants/1'11%22%3E%3Ca%20href=https:%5c%5cwww.baidu.com%3E%E8%B7%B3%E8%BD%AC%E5%88%B0%E4%B8%BB%E9%A1%B5%3Cp%3Ehttp:%5c%5coca-to-guoquan-delivery.test%3Cinput%20%20hidden='true'%20/edit
2. 事发现场一:
将路由参数的值变为
1'
,页面居然能正常展示:
3. 事发现场二:
页面被注入了
HTML
代码,并且可以展示恶意外链:
如何解决呢?
- 既然被注入了一些
奇奇怪怪
的内容,那我们就应该想办法把它给屏蔽掉。正所谓取其精华,去其糟粕。 Laravel
有一个路由参数的 正则表达式约束 功能,可以限制路由参数值的格式。芜湖~,此乃正解!!!
具体方式
- 正则表达式约束 看官方文档示例:
Route::get('/user/{name}', function (string $name) { // ... })->where('name', '[A-Za-z]+'); Route::get('/user/{id}', function (string $id) { // ... })->where('id', '[0-9]+'); Route::get('/user/{id}/{name}', function (string $id, string $name) { // ... })->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
- 这里有一个问题,官方文档上描述的都是,关于
单路由的 - 路由参数的正则限定
。可我的代码里面resources
资源路由居多,这我该怎么办? - 哎呀,不行,头有点痒,要长脑子了。
批量
、全局
等词汇浮现在脑海,我悟了… - 全局设置一下,参数名称限制 全局约束:
你应该在
App\Providers\RouteServiceProvider
类的boot
方法中定义这些模式:/** * 定义路由模型绑定、模式筛选器等。 */ public function boot(): void { Route::pattern('id', '[0-9]+'); }
- 一通操作后,我发现不行。好像这个不管作用,
事发现场一
和事发现场二
照样没有得到改善。 Dcat Admin
的路由文件是app/Admin/routes.php
路径下的,而不是routes/xxx.php
的。会不会是因为这个原因导致的。- 于是乎我在
app/Admin/routes.php
文件中增加关键代码:// ####---- 商户管理 - 商户列表 // 为什么是 pattern 的第一个参数是: merchant,可以通过命令行 php artisan route:list 查看 Route::pattern('merchant', '[0-9]+'); // 关键代码 $router->resource('merchants', Merchant\MerchantController::class);
- 最终
事发现场一
和事发现场二
得到妥善解决。Nice!!
总结
HTML
注入路由参数中,可以通过Laravel
自带的 正则表达式约束 进行约束。- 如果路由多为
resources
资源路由,可以通过全局约束
来约束,无需拆分资源路由。 - 如果全局约束不可以,可将
关键代码
放置到对应的路由文件中。 - 一般项目
resources
资源路由会很多,所以要批量维护,添加多条即可。
疑问
- 为什么在
App\Providers\RouteServiceProvider
类的boot
方法添加关键方法,对在app/Admin/routes.php
路由不行呢?/** * 定义路由模型绑定、模式筛选器等。 */ public function boot(): void { Route::pattern('id', '[0-9]+'); }
- 有知道的朋友,可以在评论区讨论。谢谢!!!
本作品采用《CC 协议》,转载必须注明作者和本文链接
页面上只展示经过
Controller
处理过的数据,即时是id
也是处理过滤过重新再给view
,不要直接在界面上展示用户输入的数据在 RouteServiceProvider 添加不起作用是因为这里的加载在dcat加载之后吧,所以看起来没效果