影刀RPA 敏感信息脱敏处理流程中的隐私保护实战作者林焱什么情况用做RPA自动化的时候你的流程经常要过手各种敏感数据采集数据时拿到了客户的手机号和身份证号存入Excel前需要部分遮盖截图中包含了员工的薪资信息分享流程截图前要把数字打码日志文件里不经意间记录了API Key和密码需要在上传前自动清理导出的CSV发给运营同事但要把姓名和联系方式做脱敏这些如果你不处理轻则被同事提醒重则违反《个人信息保护法》。但每次手动脱敏又太麻烦——这就是自动化脱敏的价值。核心场景流程中经过敏感数据需要自动脱敏再继续处理。怎么做第一步识别敏感数据的类型店群矩阵自动化突破运营极限先搞清楚你的流程里会出现哪些敏感数据数据类型示例风险等级脱敏方式手机号13812345678高遮盖中间4位身份证号320102199001011234高遮盖生日段姓名非公开张三中显示姓隐藏名邮箱zhangsancompany.com中遮盖用户名部分| 银行卡号 | 6222021234567890 | 高 | 只显示后4位 || 密码/Token | sk-abc123def456 | 极高 | 完全替换 || 地址 | 北京市海淀区中关村大街1号 | 中 | 只显示到区 |第二步手机号和身份证脱敏这两个是最常见的写一个通用脱敏类。importreclassDataMasker:数据脱敏工具staticmethoddefmask_phone(phone):手机号脱敏138****5678ifnotphoneorlen(str(phone))11:returnphone phone_strstr(phone)# 保留前3位和后4位returnphone_str[:3]****phone_str[-4:]staticmethoddefmask_id_card(id_num):身份证脱敏320102****1234ifnotid_numorlen(str(id_num))18:returnid_num id_strstr(id_num)returnid_str[:6]********id_str[-4:]staticmethoddefmask_name(name):姓名脱敏 2字张* 3字及以上张*三 ifnotname:returnnameiflen(name)1:return*eliflen(name)2:returnname[0]*else:returnname[0]*name[-1]staticmethoddefmask_email(email):邮箱脱敏zha***company.comifnotemailornotinemail:returnemail username,domainemail.split(,1)iflen(username)3:masked_userusername[0]***else:masked_userusername[:3]***returnf{masked_user}{domain}staticmethoddefmask_bank_card(card_num):银行卡号脱敏只显示后4位ifnotcard_numorlen(str(card_num))8:returncard_num card_strstr(card_num)return****card_str[-4:]staticmethoddefmask_password(text):密码完全替换return******# 使用maskerDataMasker()print(masker.mask_phone(13812345678))# 138****5678print(masker.mask_id_card(320102199001011234))# 320102********1234print(masker.mask_name(张三))# 张*print(masker.mask_name(张三丰))# 张*丰print(masker.mask_email(zhangsancompany.com))# zha***company.com第三步批量脱敏DataFrameRPA流程中最常处理的格式就是Excel/CSV → pandas DataFrame。写一个自动检测敏感列的脱敏器。importpandasaspdimportreclassDataFrameMasker:DataFrame自动脱敏# 定义敏感列检测规则SENSITIVE_PATTERNS{phone:(r^1[3-9]\d{9}$,DataMasker.mask_phone),id_card:(r^\d{17}[\dXx]$,DataMasker.mask_id_card),email:(r^[^][^]\.[^]$,DataMasker.mask_email),bank_card:(r^\d{16,19}$,DataMasker.mask_bank_card),}staticmethoddefdetect_sensitive_column(series,sample_size100):检测一列是否包含敏感数据samplesseries.dropna().head(sample_size).astype(str)iflen(samples)0:returnNoneforcol_type,(pattern,_)inDataFrameMasker.SENSITIVE_PATTERNS.items():match_countsum(1forvinsamplesifre.match(pattern,v))ifmatch_countlen(samples)*0.8:# 80%以上匹配就判定为该类型returncol_typereturnNonestaticmethoddefmask_dataframe(df,column_mappingNone): 自动脱敏DataFrame column_mapping: 手动指定列和脱敏方式如 {手机号: phone, 身份证: id_card} dfdf.copy()# 手动指定的列ifcolumn_mapping:forcol,mask_typeincolumn_mapping.items():ifcolindf.columnsandmask_typeinDataFrameMasker.SENSITIVE_PATTERNS:mask_funcDataFrameMasker.SENSITIVE_PATTERNS[mask_type][1]df[col]df[col].astype(str).apply(mask_func)# 自动检测未指定的列forcolindf.columns:ifcolumn_mappingandcolincolumn_mapping:continuecol_typeDataFrameMasker.detect_sensitive_column(df[col])ifcol_type:mask_funcDataFrameMasker.SENSITIVE_PATTERNS[col_type][1]df[col]df[col].astype(str).apply(mask_func)returndf# 示例dfpd.DataFrame({姓名:[张三,李四,王五],手机号:[13812345678,15987654321,13611112222],身份证:[320102199001011234,110101198505052345,440300199912123456],部门:[技术部,销售部,财务部],邮箱:[zhangsancompany.com,lisicompany.com,wangwucompany.com]})masked_dfDataFrameMasker.mask_dataframe(df)print(masked_df)# 手机号、身份证自动被脱敏了部门保留原样第四步日志文件敏感信息清理流程日志里经常不小心打印了密码和Token。写一个日志脱敏装饰器。importjsonimportreclassLogSanitizer:日志内容清理# 定义敏感信息匹配规则PATTERNS[(r(api_key|apikey|api-key)[:\s][\]?([A-Za-z0-9_\-]{20,})[\]?,r\1***REDACTED***),(r(token|access_token|secret)[:\s][\]?([A-Za-z0-9_\-\.]{20,})[\]?,r\1***REDACTED***),(r(password|passwd|pwd)[:\s][\]?([^\s\])[\]?,r\1***REDACTED***),(rsk-[A-Za-z0-9]{20,},sk-***REDACTED***),(rBearer\s[A-Za-z0-9_\-\.]{20,},Bearer ***REDACTED***),]classmethoddefsanitize(cls,text):清理文本中的敏感信息forpattern,replacementincls.PATTERNS:textre.sub(pattern,replacement,text,flagsre.IGNORECASE)returntextclassmethoddefsanitize_dict(cls,data):清理字典中的敏感值sensitive_keys[password,passwd,pwd,token,secret,api_key,apikey,access_token,authorization]ifisinstance(data,dict):return{k:***REDACTED***ifk.lower()insensitive_keyselsecls.sanitize_dict(v)ifisinstance(v,(dict,list))elsevfork,vindata.items()}elifisinstance(data,list):return[cls.sanitize_dict(item)foritemindata]returndata# 使用log_entryAPI调用完成urlhttps://api.example.com, tokeneyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9clean_logLogSanitizer.sanitize(log_entry)print(clean_log)# API调用完成urlhttps://api.example.com, token***REDACTED***第五步影刀流程中的脱敏节点把脱敏逻辑嵌入影刀流程最常用的场景是「抓取数据→脱敏→写入Excel」。影刀流程 ┌──────────────┐ │ 网页抓取节点 │ → 获取含敏感信息的用户列表 └──────┬───────┘ ↓ ┌──────────────┐ │ Python节点① │ → 调用DataFrameMasker自动脱敏 └──────┬───────┘ ↓ 分叉 ┌──────────────┐ ┌──────────────┐ │ Excel写入节点 │ │ 企微消息通知 │ │ (脱敏版给运营)│ │ (告警发现敏感数据已脱敏) │ └──────────────┘ └──────────────┘有什么坑坑1脱敏不可逆——小心把原始数据也覆盖了自动脱敏最常犯的错误直接把原始文件覆盖了。等会计说「这批身份证号怎么都是星号」的时候你才发现原始数据没了。解决方法始终另存为新文件绝不要覆盖原始数据。规范做法是原始数据.xlsx脱敏版_原始数据.xlsx分开保存。坑2正则匹配的边界情况手机号脱敏的正则1[3-9]\d{9}看起来很完美但遇到021-13812345678区号手机号连在一起就匹配不上了。还有境外号码、虚拟运营商170/171号段等。temu店群自动化报活动案例解决方法正则要有容错脱敏函数也要做兜底——正则没匹配上时降级为「显示前3后4」的粗暴遮盖。坑3JSON结构里藏着敏感数据你以为只脱敏了Excel的列但有个字段是JSON字符串里面嵌套了手机号和身份证号。{contacts:[{name:张三,phone:13812345678}],address:...}这种嵌套结构简单的字符串替换根本碰不到。解决方法对字符串类型的字段先尝试JSON解析如果解析成功就递归脱敏。坑4性能——大DataFrame脱敏很慢10万行的DataFrame每行都调一遍mask_phone和mask_id_cardPython的字符串处理要跑好一阵。解决方法用pandas的向量化操作代替逐行apply# 慢df[手机号]df[手机号].apply(mask_phone)# 快pandas Series的str方法底层C实现df[手机号]df[手机号].str[:3]****df[手机号].str[-4:]总结数据脱敏是RPA流程的「安全带」——不系也能开但出事了就是大事。关键原则自动识别敏感列、只脱敏不删数据、脱敏后另存新文件、定期检查日志防止泄露。