本文目录导读:

- 方案一:基于Nginx/Apache日志的流量脱敏(最常用)
- 方案二:数据库记录脱敏(MySQL Binlog / 慢查询日志)
- 方案三:集成数据脱敏中间件(GoReplay + 自定义过滤器)
- 方案四:PHP超全局变量拦截(通过AutoPrepend)
- 关键注意事项
- 简易自动化回放脚本示例
在PHP项目流量脱敏中,所谓的“回放前清理”通常指:在将线上真实流量(如Nginx日志、请求参数、数据库记录)用于本地调试、压力测试或自动化回归之前,移除或替换掉敏感字段(如手机号、身份证、密码、Token等)。
核心思路是“源头上做替换,流程上做隔离”,避免敏感数据流入非生产环境,以下是具体实现方案和代码示例:
基于Nginx/Apache日志的流量脱敏(最常用)
线上流量往往通过Web服务器日志记录,回放前需要清洗日志文件。
原理:在日志记录的那一刻或回放解析时,对特定字段进行正则替换。
示例:记录脱敏日志(推荐在应用层输出)
在PHP应用入口(如index.php)统一处理,写入日志时将敏感字段替换:
<?php
// 定义脱敏函数
function maskSensitiveData(array $data): array {
$fieldsToMask = ['password', 'credit_card', 'phone', 'id_card'];
foreach ($fieldsToMask as $field) {
if (isset($data[$field])) {
$original = $data[$field];
// 根据字段类型选择脱敏方式
if ($field === 'password') {
$data[$field] = str_repeat('*', strlen($original));
} elseif ($field === 'phone') {
// 保留前三后四
$data[$field] = substr($original, 0, 3) . '****' . substr($original, -4);
} elseif ($field === 'id_card') {
$data[$field] = substr($original, 0, 6) . '********' . substr($original, -4);
} else {
$data[$field] = '***MASKED***';
}
}
}
return $data;
}
// 在记录请求日志时调用
$logData = [
'ip' => $_SERVER['REMOTE_ADDR'],
'uri' => $_SERVER['REQUEST_URI'],
'params' => maskSensitiveData($_REQUEST),
'time' => date('Y-m-d H:i:s')
];
// 写入专用脱敏日志文件(不是普通error_log)
file_put_contents('/var/log/your_app/masked_traffic.log', json_encode($logData) . PHP_EOL, FILE_APPEND);
后续回放:直接读取masked_traffic.log即可,无需再次清洗。
数据库记录脱敏(MySQL Binlog / 慢查询日志)
如果回放流量来自数据库(如慢查询重现),需要对SQL语句或结果集脱敏。
示例:解析慢查询日志脱敏
function desensitizeSql(string $sql): string {
// 脱敏常见模式:password='xxx' → password='***'
$patterns = [
'/password\s*=\s*\'[^\']*\'/i' => "password='***'",
'/phone\s*=\s*\'[^\']*\'/i' => "phone='***'",
'/id_card\s*=\s*\'[^\']*\'/i' => "id_card='***'",
];
return preg_replace(array_keys($patterns), array_values($patterns), $sql);
}
// 读取慢查询日志每一行并处理
$lines = file('/var/log/mysql/slow-query.log');
$cleanedLines = array_map('desensitizeSql', $lines);
file_put_contents('/tmp/slow_cleaned.log', implode('', $cleanedLines));
集成数据脱敏中间件(GoReplay + 自定义过滤器)
对于高并发流量回放工具(如GoReplay、Tcpcopy),可以在中间环节加一个脱敏代理。
PHP侧实现脱敏代理脚本(适用于简单场景)
// 该脚本作为GoReplay的output-http target,接收请求并脱敏后转发
$input = file_get_contents('php://input');
$data = json_decode($input, true);
// 脱敏逻辑(同方案一)
$data['params'] = maskSensitiveData($data['params'] ?? []);
// 重新发送到真正的测试环境
$ch = curl_init('http://test-server/');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_exec($ch);
PHP超全局变量拦截(通过AutoPrepend)
使用auto_prepend_file(php.ini或.htaccess),在请求到达业务逻辑之前对$_REQUEST、$_SERVER等数据脱敏。
// prepend.php
function maskGlobalVars(): void {
$sensitiveKeys = ['password', 'token', 'credit'];
foreach ($_REQUEST as $key => &$value) {
if (in_array($key, $sensitiveKeys, true)) {
$value = is_string($value) ? str_repeat('*', strlen($value)) : '***';
}
}
// 同样处理 $_COOKIE 等
}
maskGlobalVars();
配置示例(php.ini):
auto_prepend_file = /path/to/prepend.php
关键注意事项
- 区分环境:
- 生产环境不要使用
auto_prepend.php脱敏,它会影响线上业务(如密码验证),只应在日志记录、日志导出时使用。
- 生产环境不要使用
- 不可逆与可逆:
- 密码、Token必须不可逆脱敏(全星号或哈希)。
- IP、UUID可保留部分特征(如子网掩码保留)用于回放时隔离性测试。
- 保持数据格式:
- 回放时,脱敏后的数据应保持原长度/类型(如手机号13位转成
138****1234),避免校验逻辑报错。
- 回放时,脱敏后的数据应保持原长度/类型(如手机号13位转成
- 日志分割:
建议记录两份日志:一份原始(仅生产保留且有严格访问控制),一份脱敏(用于回放、测试)。
简易自动化回放脚本示例
#!/bin/bash
# 1. 导出线上脱敏日志(假设已脱敏)
scp prod:/var/log/app/masked_traffic.log /tmp/
# 2. 读取日志并逐条回放
while IFS= read -r line; do
curl -X POST http://test-server/api \
-H "Content-Type: application/json" \
-d "$(echo $line | jq '.params')"
done < /tmp/masked_traffic.log
核心总结:不要在回放时才开始清洗,而是在流量出口(日志生成、数据库导出)时就完成脱敏,通过上述方案,你能够构建一个“生产->脱敏->传输->测试”的完整洁净链路。