导读:本期聚焦于星河创作的《如何利用视图封装敏感数据从而代替权限控制?数据脱敏与查询改写实战》,敬请观看详情。数据库里存着手机号、身份证、薪资这类敏感字段,如果只依赖应用层做权限判断,一旦有人绕过接口直接连库查询,敏感数据就裸奔了。本文介绍一种在数据库层面落地的方案:通过创建视图对敏感字段做脱敏封装,再借助查询改写让业务SQL透明地命中脱敏视图,从而在不改动业务代码的情况下实现细粒度的数据访问控制。文章会讲清视图脱敏的原理、MySQL与PostgreSQL下的具体实现步骤、查询改写的几种落地方式以及各自的适用场景,同时分析这种方案与传统权限控制的差异和常见踩坑点,帮助你构建更立体的数据安全防护体系。

应用层的权限控制做得再严密,也挡不住一条直接发往数据库的SQL。只要账号能连库,SELECT * FROM user一句就能把全部手机号和身份证拖走。与其把希望寄托在应用层,不如把防线下沉到数据库本身——用视图把敏感字段封装起来,配好脱敏规则和查询改写,让不同账号看到的同一张表呈现不同的内容。这篇文章就来完整讲讲这套方案的落地思路。

如何利用视图封装敏感数据从而代替权限控制?数据脱敏与查询改写实战

为什么视图能承担数据脱敏的职责

视图的本质是一条被命名存储的SELECT语句,数据库在执行针对视图的查询时,会先把视图定义展开,再与外部查询合并优化。这意味着视图输出的每一列,都可以是任意合法的表达式——你可以用CONCAT截断手机号中间四位,用LEFT只暴露姓氏,甚至用CASE WHEN结合CURRENT_USER()实现“按人显示”的动态脱敏。

相比直接对原始表授权,视图方案的核心优势在于“读写分离到字段级”。原始表t_user只授权给管理员账号,普通应用账号只能访问视图v_user。即使应用代码里写了SELECT *,拿到的也只是脱敏后的数据。这是一种白名单式的防护:不依赖业务代码自觉,安全边界落在数据库的权限体系里。

传统权限控制只能回答“谁能访问哪张表”,而视图脱敏能回答“谁看到的是哪个版本的数据”。对于运营人员要看统计数据、客服要看部分联系方式、开发要排查问题这类场景,往往不需要给全量明文,视图正好补上了这个缺口。

脱敏视图的具体实现

先看原始表结构,假设有一张用户表,包含手机号、身份证号、真实姓名等敏感字段。

CREATE TABLE t_user (
  id BIGINT PRIMARY KEY,
  real_name VARCHAR(50) NOT NULL,
  mobile CHAR(11) NOT NULL,
  id_card CHAR(18) NOT NULL,
  salary DECIMAL(10,2) DEFAULT 0,
  created_at DATETIME
);

脱敏规则通常分几类:手机号保留前三后四,身份证保留前六后四,姓名只留姓,金额可以取整或加噪。下面创建一个面向普通业务账号的脱敏视图。

CREATE VIEW v_user_masked AS
SELECT
  id,
  CONCAT(LEFT(real_name, 1), '**') AS real_name,
  CONCAT(LEFT(mobile, 3), '****', RIGHT(mobile, 4)) AS mobile,
  CONCAT(LEFT(id_card, 6), '********', RIGHT(id_card, 4)) AS id_card,
  ROUND(salary, -3) AS salary,
  created_at
FROM t_user;

然后用数据库自带的权限体系把访问边界锁死:回收普通账号对基表的全部权限,只授予视图的SELECT权限。这一步是整个方案能否生效的关键,如果基表权限没有回收,视图形同虚设。

-- 回收普通账号对基表的权限
REVOKE ALL PRIVILEGES ON mydb.t_user FROM 'app_read'@'%';
-- 只授予视图查询权限
GRANT SELECT ON mydb.v_user_masked TO 'app_read'@'%';

如果想让同一个视图对不同的人显示不同内容,可以在MySQL里借助CURRENT_USER()做条件判断。例如管理员看明文,其他人看脱敏值。

CREATE VIEW v_user_smart AS
SELECT
  id,
  CASE WHEN CURRENT_USER() LIKE 'admin@%'
       THEN real_name
       ELSE CONCAT(LEFT(real_name, 1), '**') END AS real_name,
  CASE WHEN CURRENT_USER() LIKE 'admin@%'
       THEN mobile
       ELSE CONCAT(LEFT(mobile, 3), '****', RIGHT(mobile, 4)) END AS mobile,
  created_at
FROM t_user;

PostgreSQL的实现思路相同,但能力更强一些。它支持Security Barrier视图,通过WITH (security_barrier)选项阻止使用者在视图谓词上做下推攻击;也可以配合session_user或自定义函数实现行级、列级的差异化输出。此外PostgreSQL还提供了规则系统(Rule)用于查询改写,后面会提到。

查询改写:让业务SQL透明命中脱敏视图

视图建好了,但业务代码里写的是FROM t_user,总不能全量改代码。这就轮到查询改写登场了。查询改写的目标是:业务SQL不改一个字,数据库或者中间层自动把对基表的引用替换成脱敏视图。

第一种方式是同名视图替换。把基表改名成t_user_raw,然后创建一个与原表同名的视图t_user。业务SQL完全无需改动,普通账号查到的自然是脱敏数据。这种做法要特别注意现有DML语句——MySQL的视图默认不可更新,除非满足可更新视图的条件。只读场景用起来最省心。

RENAME TABLE t_user TO t_user_raw;

CREATE VIEW t_user AS
SELECT
  id,
  CONCAT(LEFT(real_name, 1), '**') AS real_name,
  CONCAT(LEFT(mobile, 3), '****', RIGHT(mobile, 4)) AS mobile,
  created_at
FROM t_user_raw;

第二种方式是PostgreSQL规则改写。利用CREATE RULE或查询重写钩子,在解析阶段把对基表的查询自动重写到目标视图。一些国产数据库和中间件(比如基于Calcite的SQL解析层)也提供类似能力,可以在SQL进入数据库前完成改写。

-- PostgreSQL 规则示例:将对 t_user 的查询重定向到脱敏视图
CREATE RULE rewrite_t_user AS
ON SELECT TO t_user
DO INSTEAD
  SELECT * FROM v_user_masked;

第三种方式是代理层改写,在ShardingSphere-Proxy、MyCat这类中间件的SQL解析模块里注册改写规则,拦截到指定表的SELECT语句后做AST级替换。这种方式对数据库零侵入,还能按账号维度下发不同改写规则,适合多套业务共用一个库的场景。改写逻辑示意如下:

// 伪代码:在中间件SQL改写阶段做表名替换
String rewritten = originalSql
    .replaceAll("(?i)FROM\\s+t_user\\b", "FROM v_user_masked");

三种方式各有取舍:同名视图最简单但有DML兼容风险;数据库规则性能最好但绑定具体数据库;代理层最灵活但多了一跳链路。中小系统建议先用同名视图,规模大了再上代理层。

方案局限与常见踩坑点

视图脱敏不是银弹,有几个坑必须提前知道。首先是可更新视图的限制:包含函数表达式列的视图,MySQL不允许通过它更新基表。如果业务还需要写入,要么为写入单独开接口走存储过程,要么把脱敏列从更新路径中剥离。

其次是WHERE条件失效问题。脱敏后手机号变成了138****5678,如果业务代码里还有WHERE mobile = '13800005678'这样的查询,走视图必然查不到数据。解决办法是在视图中额外保留一个不可见或者仅限特定账号可见的查询辅助列,或者在改写层把等值查询条件改写到基表列上、只对输出列做脱敏,即“计算下推、输出脱敏”的原则。

再次是聚合与索引问题。对脱敏列做GROUP BY会导致分组失真,比如所有“张**”会被归到一组。同时视图中的函数计算无法利用基表索引,大表上全表扫描会带来性能开销,建议把脱敏字段控制在输出层,过滤和排序尽量走未脱敏的普通列。

最后要强调,视图脱敏和权限控制不是二选一的关系,而是纵深防御的两层。账号权限负责挡住不该进来的人,视图负责让进来的人只看到该看的数据。两层叠加,再配合审计日志记录每一次敏感查询,数据安全的水位才能真正提上来。落地时建议先梳理敏感字段清单,再按角色定义脱敏规则,最后灰度切换视图和权限,避免一次性上线造成业务回归。

视图脱敏数据脱敏查询改写修改时间:2026-09-04 07:18:46

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260904/50095.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。