跳转到主内容
极星编程网:以代码为星,赴技术山海!

Oracle数据库怎么实现数据脱敏_利用自定义函数动态处理

最可控的Oracle数据脱敏方式是写自定义函数:需区分15/18位身份证规则,用LENGTHB判字节、LENGTH判字符,防中文截取偏移,加空值校验,禁用REGEXP_REPLACE误匹配,并统一用IN_TYPE参数支持多类型字段。 oracle 里做数据脱敏,最可控、最贴近业务逻辑的方式就是写自定义函数——它不依赖data redaction kit这类企业版组件,也不需要改应用层代码,直接在sql里调用就行。但写错一个参数或忽略字符集差异,就可能让脱敏结果错位、截断,甚至暴露敏感段。 怎么写一个安全可用的脱敏函数(以身份证号为例) 身份证号脱敏不是简单地
SUBSTR
+
RPAD
就完事。15位和18位规则不同,末尾校验码不能被误删,汉字或空格混入时长度计算会出错。 必须先用
LENGTHB
判断字节长度,再用
LENGTH
判断字符数,避免中文导致截取偏移 18位身份证应保留前6位 + 后4位,中间8位替换成
'********'
;15位则保留前6位 + 后3位,中间6位替换 函数开头加
IF IN_STR IS NULL OR TRIM(IN_STR) = '' THEN RETURN NULL; END IF;
,防止空值或全空格输入引发异常 别用
REGEXP_REPLACE
直接匹配数字串——万一字段里有“ID:11010119900101123X”这种带前缀的,就会漏脱敏 示例片段:
CREATE OR REPLACE FUNCTION mask_idcard(p_id VARCHAR2) RETURN VARCHAR2 IS v_len NUMBER := LENGTHB(TRIM(p_id)); BEGIN IF p_id IS NULL OR TRIM(p_id) = '' THEN RETURN NULL; END IF; IF v_len = 18 THEN RETURN SUBSTR(p_id, 1, 6) || '********' || SUBSTR(p_id, -4); ELSIF v_len = 15 THEN RETURN SUBSTR(p_id, 1, 6) || '******' || SUBSTR(p_id, -3); ELSE RETURN RPAD(SUBSTR(p_id, 1, 4), LENGTH(p_id), '*'); END IF; END;
姓名、手机号、银行卡号的脱敏逻辑差异在哪 同一套函数模板不能套用所有字段类型——姓名要兼顾2字、3字、带括号(如“张三(代理)”),手机号要识别+86前缀,银行卡号得防末尾空格干扰。 姓名:2–3个汉字时只掩第二字,如“李四”→“李*”,“王小明”→“王*明”;超过4字统一掩中间50%(向下取整),用
CEIL(LENGTH(p_name)/2)
控制起始掩码位置 手机号:先
TRANSLATE(p_phone, '+0123456789', '00000000000')
剔除非数字字符,再判断长度;11位保留前3后4,中间4位掩成
'****'
银行卡号:优先用
REGEXP_REPLACE(p_card, '[^0-9]', '')
清洗,再按长度分支处理;超16位一律取前4 + 后4,中间补
'********'
所有函数都建议加
IN_TYPE
参数(如
1=姓名, 2=身份证, 4=手机号
),避免为每个字段建一个函数,维护成本翻倍 为什么不能直接用
MD5
或
DES
函数做脱敏 加密 ≠ 脱敏。很多团队误把
fn_md5
当脱敏方案,结果上线后发现三类问题集中爆发: oracle知识库 oracle知识库下载 下载
fn_md5
输出是32位十六进制字符串,原字段是18位身份证,长度不一致 → 应用层格式校验失败、前端展示错行
DBMS_OBFUSCATION_TOOLKIT.DES
需要密钥且依赖
ZHS16GBK
字符集,一旦数据库字符集是
AL32UTF8
,
UTL_I18N.STRING_TO_RAW
会静默截断中文,脱敏后出现乱码或NULL 加密函数无法满足“可读性要求”:审计、测试、客服查单都需要看到“张*”“138****1234”这种结构化模糊值,而不是一串不可逆哈希 性能上,
MD5
每次调用都要走RAW转换+哈希运算,比纯字符串操作慢3–5倍,在百万级查询中明显拖慢报表 函数上线前必须验证的三个边界场景 写完函数别急着提交,这三类数据一跑就露馅: 含全角空格、换行符、制表符的字段:
'110101 19900101 123X'
—— 必须先
TRIM(TRANSLATE(p_id, CHR(9)||CHR(10)||CHR(13), ' '))
清理控制字符 混合中英文+数字的地址字段:
'北京市朝阳区建国路8号SOHO现代城A座1001'
—— 用
LENGTH
截取会把“SOHO”切半,得改用
INSTR
定位关键分隔符或按语义分段处理 空值、超长值、特殊符号前缀:
NULL
、
'***'
、
'[已注销]13812345678'
—— 函数里没加
WHEN OTHERS THEN RETURN '[MASKED]';
的兜底,就会报
ORA-06502
中断整个查询 真正难的不是写出第一个脱敏函数,而是让同一个函数在身份证、护照号、港澳通行证、外国人永久居留证等十几种证件类型下,都保持头部/尾部可见、中间可配置、长度不变形、无字符集陷阱——这些细节不压到具体字段去测,光看文档永远发现不了。

相关文章