直接对原始json字符串用正则脱敏可行但需谨慎:精准匹配键名、安全捕获值、保留格式;须处理跨行、转义、注释等陷阱,并按值类型差异化脱敏。

直接对原始 JSON 字符串(未解析为对象)用正则表达式脱敏,是可行但需谨慎的方案——适用于无法或不希望解析 JSON 的轻量场景(如日志预处理、网关层快速过滤),但必须避开 JSON 结构陷阱(如嵌套、引号转义、字段名重复等)。核心思路是:**精准匹配键名 + 安全捕获值 + 保留原始格式**。
识别敏感字段的键值对模式
不能简单写 "phone": "138...",因为 JSON 中键名和值可能跨行、含空格、有转义引号。推荐使用惰性匹配 + 带边界的模式:
-
基础结构:
"s*(phone|idCard|email|password)s*"s*:s*("([^"\]|\.)*"|true|false|null|-?d+(?:.d*)?(?:[eE][+-]?d+)?) -
说明:匹配双引号包裹的敏感键名(忽略周围空白),冒号后允许空白,再匹配字符串(支持转义)、布尔、null 或数字;用非贪婪
[^"\]*防止跨字符串误匹配 -
注意:不匹配单引号 JSON(非标准),也不处理键名带转义(如
""phone""),这类极少,若存在需前置预清理
对不同值类型执行差异化脱敏
值的类型决定脱敏方式,正则需分组捕获并判断:
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
-
字符串值(第3组匹配内容):保留开头2位 +
"****"+ 末尾1位(如"138****0001");邮箱可留用户名首尾+域名("u***@domain.com") -
数字/布尔/null:数字可替换为
0或***;布尔统一为false;null 保持不变或替为null -
实现提示:在 replace 回调中用
if (match[3]) {...}判断是否为字符串,避免误脱敏数字
规避 JSON 结构风险的关键细节
原始字符串操作易出错,以下三点必须处理:
-
跳过注释与字符串内内容:JSON 标准无注释,但实际日志中可能出现
//或/* */。若存在,需先移除注释(用正则//*[sS]*?*/|//.*/g),否则可能把注释里的"phone"当成字段脱敏 -
防止匹配到值中的键名:例如
"content": "user phone: 138..."。通过要求键名前后必须是"+ 空白 +:(即"s*keys*"s*:)来降低误伤 -
保留原始缩进与换行:replace 时用
$&(整个匹配)做占位,只替换值部分,确保 JSON 格式不变,利于后续解析或展示
一个可用的 JavaScript 示例
以脱敏 phone、idCard、email 为例:
const sensitiveKeys = ['phone', 'idCard', 'email'];
const pattern = new RegExp(
'"\s*(' + sensitiveKeys.join('|') + ')\s*"' + // 匹配键
'\s*:\s*' + // 冒号及空格
'(' + // 值(捕获组2)
'"([^"\\]|\\.)*"' + // 字符串(支持转义)
'|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?' + // 其他字面量
')',
'g'
);
<p>function desensitizeJSON(jsonStr) {
return jsonStr.replace(pattern, (match, key, value) => {
if (value.startsWith('"')) {
const inner = value.slice(1, -1); // 去掉引号
let masked;
if (key === 'phone') masked = inner.length > 4 ? inner.substring(0, 3) + '<strong><strong>' + inner.slice(-1) : '</strong></strong>';
else if (key === 'idCard') masked = inner.length > 16 ? inner.substring(0, 4) + '<strong>****</strong>' + inner.slice(-4) : '<strong>****</strong>';
else if (key === 'email') {
const [user, domain] = inner.split('@');
masked = user ? (user[0] + '<strong><em>@' + (domain || '')) : '</em></strong>@<strong><em>';
}
return <code>"${key}": "${masked}"</code>;
}
return `"${key}": "</em></strong>"`; // 非字符串值统一掩码
});
}</p>










