应通过全局中间件在控制器执行前捕获原始请求体(getrawcontent()或query_string),结构化记录未过滤参数,并禁用input()的filter参数,确保日志中保留用户真实输入;同时在validateexception捕获时同步记录完整上下文,使用独立audit日志通道。

如果您在ThinkPHP应用中需要对用户提交的请求参数进行完整、可审计的记录,但当前日志中仅存过滤后或部分字段,则说明原始输入未被结构化捕获。以下是实现请求参数审计级记录的多种方法:
一、通过全局中间件捕获原始请求体并结构化记录
该方法确保在任何业务逻辑执行前获取未处理的原始数据,避免input()或param()自动过滤导致审计失真。适用于POST/PUT/DELETE等含body的请求类型。
1、创建中间件文件app/middleware/RecordRawParamMiddleware.php,定义handle方法接收$request和$next。
2、在handle开头调用$request->getRawContent()获取原始请求体;若为空,则跳过记录。
3、对非空原始内容尝试json_decode($raw, true),成功则将结果作为raw_param存入日志;失败则保留原始字符串并标记format_error。
4、同时调用$request->server('QUERY_STRING')获取GET参数原始查询串,并用parse_str()解析为数组,保留编码差异(如%20与空格)。
5、使用Log::channel('audit')->info('raw_param_capture', [ 'ip' => $request->ip(), 'url' => $request->url(true), 'method' => $request->method(), 'raw_param' => json_encode($rawData, JSON_UNESCAPED_UNICODE), 'create_time' => date('Y-m-d H:i:s') ]);。
二、在验证失败时同步记录完整上下文
该方法聚焦于合法性校验环节,确保每次ValidateException抛出时,攻击者提交的非法参数立即落库,防止绕过校验的畸形输入无迹可查。
1、新建中间件app/middleware/AuditValidateFail.php,捕获ValidateException异常。
2、在catch块中调用$request->param()获取当前已解析参数(注意:此值可能已被过滤,需配合raw_param使用)。
3、提取异常信息:$e->getMessage()与$e->getRule()(ThinkPHP 6.1+支持)。
4、构造审计日志数组,必须包含:ip、method、url、controller、action、param(JSON编码)、rule、msg、create_time。
5、强制使用独立日志通道Log::channel('audit')写入,避免与业务日志混杂。
三、基于请求生命周期钩子统一注入参数快照
该方法利用中间件的before/after机制,在控制器执行前后分别记录参数状态,适用于需比对操作前后差异的敏感行为审计场景。
1、在中间件handle方法中,调用$request->except(['token', 'sign', 'password'])过滤高敏键,再用$request->param()获取全量参数。
2、将过滤后的参数存入$request->withAttr('audit_params_before', $params)供后续使用。
3、在after方法中再次获取$response,并从$request->attr('audit_params_before')取出原始快照。
4、若响应体中包含业务code字段(如['code'=>0]),且请求方法为POST/PUT/DELETE,则触发审计记录。
5、日志内容中必须包含:session_id()、user_id(通过Auth::id()或$request->attr('user')['id']获取)、audit_params_before。
四、使用路由绑定中间件实现按模块差异化记录
该方法避免全局记录带来的性能开销与日志噪音,仅对admin、api/v1/user等指定路由组启用完整参数审计。
1、在route/app.php中为敏感路由组添加中间件:Route::group('admin', function () { ... })->middleware('RecordRawParamMiddleware');。
2、在中间件内部判断当前路由是否匹配预设规则,例如preg_match('/^admin\//i', $request->rule()->getRuleName())。
3、匹配成功后,执行与方法一相同的raw_param捕获流程。
4、不匹配时直接return $next($request),跳过记录逻辑。
5、所有记录动作必须异步化处理,推荐推送至Redis队列,由独立消费者进程写入数据库,严禁在中间件中同步执行DB::insert()或file_put_contents()。
五、禁用input()第三参数以保障原始输入可见性
该方法从源头杜绝因自动过滤导致审计数据失真的风险,确保日志中呈现的是用户真实提交内容,而非框架转义结果。
1、全局搜索项目中所有input()调用,删除第三个filter参数,例如将input('content', '', 'htmlspecialchars')改为input('content')。
2、在业务逻辑中显式调用htmlspecialchars()或strip_tags()进行输出安全处理,分离“记录”与“展示”职责。
3、在中间件记录阶段,优先使用$request->getRawContent()或$request->server('QUERY_STRING'),而非input()或$request->param()。
4、对已存在的input()调用,添加注释标记// DO NOT FILTER FOR AUDIT,防止后续误加filter参数。
5、配置CI/CD流水线,在代码扫描阶段拦截含input(.*?,.*?,.*?')模式的提交,阻断带filter参数的input调用进入生产环境。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











