codeigniter需在model层或php层统一实现字段级脱敏,推荐用白名单配置+自定义helper封装规则,避免controller/view硬编码;动态脱敏须结合角色判断并区分缓存键。

CodeIgniter 本身不内置数据脱敏功能,但可以在模型层、结果集处理或视图输出前插入轻量级脱敏逻辑。关键不是“加插件”,而是控制数据流出路径——在哪脱、怎么脱、是否可逆,直接决定安全水位。
在 Model 中对查询结果做字段级脱敏
这是最可控、侵入最小的方式。适用于开发/测试环境静态脱敏,或客服类后台需按角色展示部分敏感信息的场景。脱敏发生在数据从数据库取出后、返回给控制器之前,原始数据不受影响。
- 使用
select()+as别名配合 SQL 字符串函数(如 MySQL 的CONCAT()、LEFT())直接在查询中脱敏,例如:SELECT id, CONCAT(LEFT(mobile, 3), '****', RIGHT(mobile, 4)) AS mobile FROM users
- 更推荐在 PHP 层统一处理:在 Model 的
get()或find()方法返回结果前,遍历数组对指定字段调用脱敏工具函数,比如:foreach ($users as &$u) { $u['mobile'] = $this->desensitize_mobile($u['mobile']); } - 避免在
select('*')后硬编码字段名;建议维护一个脱敏字段白名单配置(如$desensitize_fields = ['mobile', 'idcard', 'email']),便于后续扩展和审计
用自定义 Helper 封装常用脱敏规则
把手机号、身份证、邮箱等脱敏逻辑抽成独立函数,放在 app/Helpers/desensitize_helper.php,加载后随处可用。不依赖第三方库,也规避了框架升级带来的兼容风险。
- 手机号脱敏:
function desensitize_mobile($str) { return preg_replace('/^(\d{3})\d{4}(\d{4})$/', '$1****$2', $str); } - 身份证脱敏(保留前3后4):
function desensitize_idcard($str) { return preg_replace('/^(\d{3})\d{10}(\d{4})$/', '$1**********$2', $str); } - 邮箱脱敏(保留用户名首尾+域名):
function desensitize_email($str) { return preg_replace('/^(.)(.*?)(@.*)$/', '$1***$3', $str); } - 注意:正则需校验输入长度和格式,空值或非法字符串(如
null、'')应原样返回,避免触发 Notice
避免在 Controller 或 View 中硬编码脱敏逻辑
Controller 是协调层,View 是展示层,两者都不该承担数据变形职责。否则极易出现同一字段在不同页面脱敏不一致(比如列表页只掩码中间4位,详情页却全隐藏),也难以统一管控策略变更。
- 常见错误:
$data['user']['mobile'] = substr($user->mobile, 0, 3) . '****' . substr($user->mobile, -4);写在 Controller 里——下次加个新接口就得重复写一遍,漏改一处就成隐私漏洞 - View 中用
substr()直接切字符串更危险:无法复用规则、不能做格式预检、JSON API 接口根本绕过 View,导致脱敏失效 - 正确做法:所有敏感字段必须经由 Model 或专用 Service 类输出,脱敏是“出库必经关卡”,不是“前端补丁”
动态脱敏需结合身份与上下文判断
生产环境真正需要的是“谁看、看多少”的权限感知脱敏。CodeIgniter 没有原生 RBAC,但可通过 Session 或 JWT 载荷中的角色标识,在 Model 脱敏函数中加入条件分支。
- 例如:
if ($this->session->role === 'admin') { return $str; } else { return desensitize_mobile($str); } - 不要把角色判断写死在 Helper 函数里——应作为参数传入,或由 Model 从服务容器中获取当前用户上下文
- 特别注意缓存场景:若使用
cache()->save()缓存了已脱敏结果,需确保缓存键包含用户角色维度(如"user_list_admin"/"user_list_operator"),否则高权限用户缓存会污染低权限用户响应
脱敏真正的复杂点不在代码几行,而在规则边界:身份证号在风控模型中可能需要保留出生年份用于年龄分群,但测试库又必须彻底模糊化;手机号在短信网关日志里得留完整,而客服工单界面只能显示 138****0000。这些都得靠字段级策略配置驱动,而不是写死在某个 helper 里。











