资讯动态

PostgreSQL笔记59:行列级权限机制与数据脱敏实践

发布时间:2026/8/24 14:52:00 来源:尧图企业网站定制
纲要列级权限Column-Level Privileges授权粒度与适用操作SELECT、INSERT、UPDATE、DELETE结合视图与函数的细粒度控制行级安全Row-Level Security, RLS策略POLICY的创建与组合策略表达式与内置函数CURRENT_USER、CURRENT_SETTING默认否定权限与绕过机制BYPASSRLSWITH CHECK与USING表达式的区别数据脱敏方案对比静态脱敏工具pg_anonymizer、pg_dump脱敏导出动态脱敏实现视图方式 vs Rust 重构的pg_dynamic_mask权限元数据查询\z与pg_class、pg_attributeAPI 速览完整 Demo基于 Node.js pg驱动官方文档与参考链接列级权限精确到字段的访问控制PostgreSQL 支持将权限细化到表的特定列从而满足“不同用户只能访问某些敏感字段”的需求。例如员工表中包含employee_id、forename、salary等列人事专员只需读取前两列而无权查看薪资。列级权限适用于SELECT、INSERT、UPDATE操作但DELETE针对整行因此不支持列级授权。实现方式是通过GRANT语句指定列名-- 创建测试表CREATETABLEemployees(employee_idSERIALPRIMARYKEY,forenameTEXT,surnameTEXT,salaryNUMERIC);-- 创建专用角色CREATEROLE hr_read;-- 仅授予对 employee_id 和 forename 的 SELECT 权限GRANTSELECT(employee_id,forename)ONemployeesTOhr_read;当hr_read用户执行SELECT * FROM employees时会因权限不足而报错只有显式查询被授权的列才能正常返回。若需授予更新权限同理GRANTUPDATE(salary)ONemployeesTOpayroll_admin;借助视图或函数列级权限还可实现更复杂的转换如对身份证号脱敏显示但视图本身不具备列级权限的精细度仍需底层表授权配合。行级安全RLS基于行内容的动态过滤行级安全允许定义策略POLICY使不同用户只能看到满足特定条件的行。典型场景如医疗信息系统医生只能查看其负责病人的记录。启用行级安全默认情况下表不启用 RLS需显式开启ALTERTABLEpatientsENABLEROWLEVELSECURITY;启用后若未创建任何策略则所有非表所有者或非超级用户的普通用户对该表的查询、更新、删除将返回空结果即“默认否定权限”。这是 RLS 的核心安全原则除非策略明确放行否则拒绝访问。创建策略策略的语法为CREATEPOLICY policy_nameONtable_name[AS{ PERMISSIVE|RESTRICTIVE }][FOR{ALL|SELECT|INSERT|UPDATE|DELETE}][TO{ role_name|PUBLIC}][USING(condition)][WITHCHECK(condition)];USING控制哪些行可以被操作对于SELECT、UPDATE、DELETE生效。WITH CHECK控制新行或修改后的行是否符合策略对于INSERT、UPDATE生效。示例让每个用户只能看到username等于当前会话用户的记录。CREATETABLEtest(idSERIAL,usernameTEXT,ageINT);ALTERTABLEtestENABLEROWLEVELSECURITY;CREATEPOLICY user_policyONtestUSING(usernameCURRENT_USER)WITHCHECK(usernameCURRENT_USER);此时用户u1查询test仅返回username u1的行插入时若username不是u1则违反WITH CHECK操作将被拒绝。策略组合一个表可拥有多个策略它们的关系由AS子句决定PERMISSIVE默认多个策略条件使用OR组合任一通过即可。RESTRICTIVE多个策略条件使用AND组合必须全部通过。例如先定义一个宽松策略允许访问自己部门的数据再加一个限制性策略禁止访问敏感标记的行。绕过行级安全超级用户默认拥有BYPASSRLS属性可忽略所有策略。普通用户也可被授予该属性ALTERROLE auditor BYPASSRLS;通过current_setting等函数可实现更灵活的策略例如基于应用参数动态过滤。数据脱敏静态与动态方案保护敏感信息PII通常需要脱敏处理。PostgreSQL 生态中常见的工具分为两类。静态脱敏直接修改原始数据生成一份脱敏后的副本。代表工具pg_anonymizerCLI 工具通过 YAML 配置文件定义规则一键执行后原地替换数据具备破坏性。pg_dump 脱敏导出先导出为 SQL 文件在导出过程中对敏感列进行替换再导入新库不破坏源库。静态脱敏适合数据交付、测试环境搭建但无法满足“同一份数据对不同用户呈现不同内容”的需求。动态脱敏在不改变原始数据的前提下根据用户角色动态屏蔽或变形敏感字段。早期实现常通过视图来完成例如CREATEVIEWpatients_viewASSELECTid,name,CASEWHENcurrent_userdoctor_maryTHENphoneELSE***ENDASphoneFROMpatients;但视图方案维护复杂且难以处理行级过滤。更专业的工具如pg_dynamic_mask前身为pg_dynamic_mask1.0 基于视图2.0 用 Rust 重构可通过策略直接作用于底层表实现角色感知的动态脱敏并支持多种掩码策略。权限元数据查询使用\z或\dp可在 psql 中查看表的权限信息\z employees输出中arwdDxt等字母表示不同权限a INSERTr SELECTw UPDATEd DELETED TRUNCATEx REFERENCESt TRIGGER也可查询系统表pg_class、pg_attribute和pg_namespace获取更详细的信息。API 速览本节汇总涉及的核心 SQL 命令与函数。授权命令命令说明适用版本GRANT SELECT (col1, col2) ON table TO role;授予列级 SELECT 权限8.0GRANT UPDATE (col) ON table TO role;授予列级 UPDATE 权限8.0ALTER TABLE table ENABLE ROW LEVEL SECURITY;启用行级安全9.5CREATE POLICY ...创建行安全策略9.5ALTER ROLE role BYPASSRLS;赋予绕过 RLS 权限9.5策略表达式常用函数函数说明CURRENT_USER当前会话用户名SESSION_USER会话初始用户名CURRENT_SETTING(app.param)读取自定义配置参数可用于传递上下文元数据查询-- 查看表上所有策略SELECT*FROMpg_policiesWHEREtablenametest;-- 查看角色属性是否包含 bypassrlsSELECTrolname,rolbypassrlsFROMpg_roles;完整 Demo基于 Node.js 的行级安全实践本 Demo 使用 Node.js 驱动pg库演示不同数据库用户通过 RLS 自动过滤数据。项目结构demo-rls ├── package.json ├── init.sql -- 初始化表、角色、策略 ├── index.js -- 主程序 └── .env -- 数据库连接配置初始化脚本init.sql-- 创建测试表CREATETABLEIFNOTEXISTSuser_data(idSERIALPRIMARYKEY,usernameTEXTNOTNULL,secret_infoTEXT);-- 启用 RLSALTERTABLEuser_dataENABLEROWLEVELSECURITY;-- 创建策略仅允许用户看到其 own 行CREATEPOLICY user_own_policyONuser_dataUSING(usernameCURRENT_USER)WITHCHECK(usernameCURRENT_USER);-- 插入示例数据INSERTINTOuser_data(username,secret_info)VALUES(alice,Alice secret),(bob,Bob secret),(charlie,Charlie secret);-- 创建数据库角色与系统用户对应CREATEROLE alice LOGIN PASSWORDalice123;CREATEROLE bob LOGIN PASSWORDbob123;GRANTSELECT,INSERT,UPDATE,DELETEONuser_dataTOalice,bob;GRANTUSAGEONSEQUENCE user_data_id_seqTOalice,bob;Node.js 主程序index.js使用pg连接池模拟多用户并发查询。const{Pool}require(pg);// 连接配置超级用户用于创建连接实际使用时可切换角色constsuperPoolnewPool({host:localhost,port:5432,database:testdb,user:postgres,password:postgres});// 模拟不同用户的查询asyncfunctionqueryAsUser(username,password){constpoolnewPool({host:localhost,port:5432,database:testdb,user:username,password:password});try{constresawaitpool.query(SELECT * FROM user_data ORDER BY id);console.log(--- Data for${username}---);res.rows.forEach(rowconsole.log(row));}finally{awaitpool.end();}}asyncfunctionrunDemo(){// 先以超级用户查看全部console.log(--- Superuser sees all ---);constallawaitsuperPool.query(SELECT * FROM user_data);all.rows.forEach(rowconsole.log(row));// 分别以 alice 和 bob 查询awaitqueryAsUser(alice,alice123);awaitqueryAsUser(bob,bob123);awaitsuperPool.end();}runDemo().catch(console.error);运行说明创建 PostgreSQL 数据库testdb执行init.sql初始化。安装依赖npm init -y npm install pg dotenv。配置.env或直接修改连接信息。运行node index.js。输出预期超级用户能看到所有行alice、bob、charlie。alice用户仅能看到username alice的行。bob用户仅能看到username bob的行。技术点总结行级安全策略的启用与创建。多用户角色隔离查询。通过CURRENT_USER实现动态过滤。超级用户绕过策略的能力。项目难点与解决方案针对 RLS 生产落地核心难点策略的默认否定行为导致普通用户初始无法访问需谨慎设计。多个策略的PERMISSIVE/RESTRICTIVE组合容易产生逻辑混淆。动态脱敏与行级过滤的结合需要额外函数支持。解决方案分阶段上线先启用 RLS 但创建宽松策略如USING (true)保证现有业务不中断再逐步收紧。明确策略优先级统一使用RESTRICTIVE作为全局黑名单PERMISSIVE作为白名单。采用CURRENT_SETTING传递应用层用户属性实现更细粒度的动态策略。广度覆盖 SQL 权限体系、数据脱敏工具、元数据查询。深度深入策略表达式的执行机制区分USING与WITH CHECK的不同阶段。复杂度多租户场景下策略可能多达数十个需结合pg_policies视图进行审计。官方文档PostgreSQL 官方文档行级安全https://www.postgresql.org/docs/current/ddl-rowsecurity.html权限授予https://www.postgresql.org/docs/current/sql-grant.html策略创建https://www.postgresql.org/docs/current/sql-createpolicy.html参考链接pg_anonymizer项目https://github.com/raphaelauv/pg_anonymizerpg_dynamic_mask介绍Rust 重构https://github.com/daamien/pg_dynamic_mask列级权限实践示例https://wiki.postgresql.org/wiki/Column_level_privileges总结PostgreSQL 提供了列级权限与行级安全两大精细控制机制分别作用于字段和记录层面为多租户应用、隐私合规场景提供了原生支持。列级权限通过GRANT指定列名实现而行级安全则依赖策略表达式并配合USING/WITH CHECK完成读写过滤。结合静态或动态脱敏工具可构建完整的敏感数据保护体系。实际部署时需注意默认否定行为、策略组合规则以及超级用户的绕过权限以确保业务平滑迁移。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价