适用场景
在业务系统开发与运维过程中,日志记录、错误提示、数据库备份等环节极易泄露用户敏感信息。常规做法是在输出前手动调用脱敏函数,但面对多种敏感类型(手机号、身份证、银行卡、邮箱、姓名)时,重复编写正则不仅低效,且容易遗漏新类型或格式变种。
数据脱敏API提供了开箱即用的敏感信息检测与掩码能力,可集成到日志框架、网关过滤、数据清洗管道或前端展示层,无需自行维护正则规则。典型场景包括:
- 日志脱敏:在Logback或Log4j2的Appender中调用,确保日志文件不包含明文敏感字段。
- 接口返回值脱敏:在REST API响应序列化前对敏感字段进行掩码,防止信息泄漏给非授权客户端。
- 数据导出脱敏:批量查询数据库后,对结果集中的敏感列统一脱敏再导出到CSV或报表。
- 测试数据生成:对生产环境导出数据进行脱敏后供测试环境使用。
接口能力边界
- 检测类型:支持手机号(国内11位)、身份证(15/18位)、银行卡(16-19位)、邮箱、中文姓名(2-4字常见姓名)。所有匹配基于纯本地正则,无需联网,毫秒级返回。
- 请求限制:单次text最长50000字节(约5万字符),QPS限制10/s。如文本过长需业务侧分片。
- 掩码规则:默认不保留原文,仅返回掩码后的文本及检测位置。可通过
with_original参数在detections中附带原始值(仅供调试,生产建议关闭)。 - 类型组合:支持逗号分隔指定需脱敏的类型(如
phone,email),或使用all覆盖全部类型。
请求参数与鉴权
鉴权方式
通过HTTP HeaderX-API-Key传递API密钥(从平台获取)。示例如下:
X-API-Key: <your-api-key>请求体字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
text | string | 是 | 待脱敏的原始文本,最长50000字节。 |
types | string | 否 | 需要脱敏的类型,逗号分隔;默认all。可选值:phone、idcard、bankcard、email、name。 |
with_original | boolean | 否 | 是否在detections中回显原始敏感值,默认false。 |
注意:
text字段应传入字符串,若传入非字符串类型(如数字),API会返回参数校验错误。
快速接入:curl 示例
以下示例演示对一个包含姓名和手机号的文本进行脱敏,仅对姓名和手机号进行掩码(设置types=name,phone)。
curl -sS -X POST \ -H "X-API-Key: ${APIZERO_API_KEY}" \ -H "Content-Type: application/json" \ -d '{ "text": "联系人:张三,电话 13812345678", "types": "name,phone", "with_original": false }' \ "https://v1.apizero.cn/api/desensitize"执行后预期返回:
{ "code": 0, "data": { "detection_count": 2, "detections": [ {"masked": "张*", "type": "name"}, {"masked": "138****8000", "type": "phone"} ], "masked_text": "联系人:张*,电话 138****8000", "summary": {"name": 1, "phone": 1}, "types_applied": ["name", "phone"] }, "msg": "成功" }Java 代码接入(Spring Boot 示例)
以下是用RestTemplate发送POST请求的典型实现。注意需要将API密钥配置在application.yml中。
1. 添加依赖(Maven)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>2. 配置类
@Component public class DesensitizeClient { private static final String API_URL = "https://v1.apizero.cn/api/desensitize"; private final RestTemplate restTemplate; private final String apiKey; public DesensitizeClient(@Value("${apizero.api-key}") String apiKey) { this.restTemplate = new RestTemplate(); this.apiKey = apiKey; } public DesensitizeResponse desensitize(String text, String types, boolean withOriginal) { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); headers.set("X-API-Key", apiKey); Map<String, Object> body = new HashMap<>(); body.put("text", text); body.put("types", types); body.put("with_original", withOriginal); HttpEntity<Map<String, Object>> request = new HttpEntity<>(body, headers); ResponseEntity<DesensitizeResponse> response = restTemplate.postForEntity(API_URL, request, DesensitizeResponse.class); return response.getBody(); } }3. 响应DTO
public class DesensitizeResponse { private int code; private Data data; private String msg; // getters & setters public static class Data { private int detection_count; private List<Detection> detections; private String masked_text; private Map<String, Integer> summary; private List<String> types_applied; // getters & setters } public static class Detection { private String masked; private String type; // 当 with_original=true 时包含 original 字段 private String original; // getters & setters } }4. 调用示例
@RestController public class DemoController { @Autowired private DesensitizeClient client; @PostMapping("/logs") public String processLog(@RequestBody String rawLog) { DesensitizeResponse resp = client.desensitize(rawLog, "all", false); if (resp.getCode() == 0) { return resp.getData().getMasked_text(); } else { throw new RuntimeException("脱敏失败: " + resp.getMsg()); } } }返回值详解
| 字段 | 类型 | 说明 |
|---|---|---|
code | int | 0表示成功,非0表示错误 |
msg | string | 状态描述 |
data.masked_text | string | 脱敏后的完整文本 |
data.detection_count | int | 检测到的敏感信息总数 |
data.detections | array | 每个被检测到的敏感条目,包含masked(掩码后值)和type(类型) |
data.summary | object | 按类型统计检测次数,例如{"phone": 2, "name": 1} |
data.types_applied | array | 本次实际启用的脱敏类型列表(由服务端根据传入types解析后确定) |
data.detections[].original | string | 仅当with_original=true时存在,为原始值。生产环境建议关闭。 |
常见错误码与排查
| 错误码 | 含义 | 排查方向 |
|---|---|---|
| -1 | 系统内部错误 | 检查请求格式,联系技术支持。 |
| 1001 | 缺少X-API-Key头 | 确认请求头携带正确,且API密钥未过期。 |
| 1002 | API Key 无效 | 检查密钥是否正确或是否被封禁。 |
| 2001 | 请求体解析失败 | 确认Content-Type为application/json,且JSON语法正确。 |
| 2002 | text长度超过50000字节 | 对长文本分片后分别请求。 |
| 2003 | types参数包含非法值 | types仅支持phone,idcard,bankcard,email,name,all。 |
| 2004 | text为空或非字符串 | 确认传入JSON中text字段为有效非空字符串。 |
工程化注意事项
- QPS 控制:接口限制10/s,建议在客户端加入限流或重试机制(如Resilience4j)。若单次任务需要处理大量文本,分批发送并控制并发数。
- 超时设置:考虑到文本长度和网络延迟,HTTP连接超时建议设置10秒,读取超时30秒。
- 数据完整性:
masked_text返回脱敏后文本,但detections仅报告匹配到的片段。如果某段敏感信息被斜杠或空格分割(如“138 1234 5678”),可能无法被正则捕获。建议在调用前对文本做规范化处理(如移除空格)。 - 日志集成:在Logback的
MessageConverter或Encoder中调用此API时,需注意不要产生循环依赖(脱敏APIs日志本身也需要脱敏)。推荐在应用层统一封装日志工具类,而非在日志框架底层直接调用。 - 性能测试:虽然毫秒级返回,但在高并发日志场景下,每次I/O开销不可忽视。可考虑本地缓存脱敏规则或使用批量接口(当前无批量接口,需自行聚合)。
- 中文姓名脱敏:姓名检测依赖常见姓氏+1-2字名,对于复姓(如“欧阳”)或少数民族长名可能识别为多个片段。需在业务层补充样本测试。
- 数据留存:
with_original打开后,原始值会随响应返回,请确保不在服务器日志中打印原始响应体,避免二次泄漏。
参考文档
- 数据脱敏 API 文档
- 原始文档(Markdown)
提示:文档中包含完整的参数说明与更多示例,接入前建议仔细阅读。