RLS(Row-Level Security,行级安全)

一、基础定义

RLS 是数据库原生行粒度访问控制能力,区别于传统仅能控制整张表的 GRANT 表权限,可通过策略规则限制角色 / 会话只能看到、修改表中满足条件的行,所有 DML(SELECT/INSERT/UPDATE/DELETE)都会自动追加过滤条件,对上层应用透明执行。

主流支持数据库:PostgreSQL(9.5+,生态最完善)、SQL Server 2016+、CockroachDB、BigQuery;BI 工具(Tableau/Power BI)也有同名 RLS(报表行过滤)。

行业最常用场景:SaaS 多租户数据隔离。

二、核心原理(PostgreSQL 标准实现)

2.1 启用开关
-- 普通开启:表所有者/超级用户默认绕过RLS
ALTER TABLE 表名 ENABLE ROW LEVEL SECURITY;
-- 强制开启:所有人(含表主、超级用户)都受策略约束,生产推荐
ALTER TABLE 表名 FORCE ROW LEVEL SECURITY;

开启后若无任何策略,所有行全部不可访问(默认拒绝)

2.2 策略两大核心子句
子句 作用 生效操作
USING (条件) 读过滤:匹配条件的行才可见、可删/改 SELECT / UPDATE / DELETE
WITH CHECK (条件) 写校验:新增/更新后的行必须满足条件,否则直接报错 INSERT / UPDATE
2.3查询自动重写

用户写 SELECT * FROM orders; 数据库底层自动拼接策略条件:

SELECT * FROM orders WHERE tenant_id = 当前会话租户ID;

无论 ORM、原生 SQL、批量操作,无法绕过,解决应用层漏写过滤导致的数据泄露风险。

2.4 会话上下文传参

应用登录后设置会话变量,策略读取变量做隔离:

SET app.tenant_id = 10086; -- 会话级,连接销毁失效
current_setting('app.tenant_id') -- 策略内读取

三、策略语法与示例(多租户标准模板)

-- 1. 建租户订单表
CREATE TABLE orders (
    id bigserial primary key,
    tenant_id int not null, -- 租户标识
    amount numeric
);

-- 2. 开启强制RLS
ALTER TABLE orders FORCE ROW LEVEL SECURITY;

-- 3. 创建全局隔离策略(所有角色、所有操作)
CREATE POLICY tenant_isolate ON orders
FOR ALL -- 作用于SELECT/INSERT/UPDATE/DELETE
TO PUBLIC -- 所有数据库角色生效
USING (tenant_id = current_setting('app.tenant_id')::int)
WITH CHECK (tenant_id = current_setting('app.tenant_id')::int);

效果:

  • 查询:只能查到自己租户订单;
  • 新增 / 修改:强制 tenant_id 等于当前租户,无法插入别人租户数据。

四、典型业务场景

1.SaaS 多租户隔离(最主流)
单表存储全部客户数据,靠tenant_id隔离,杜绝代码漏过滤导致跨租户数据泄露,Supabase、PostgREST 核心依赖 RLS。

2.用户私有数据隔离
订单、个人资料表:用户仅能读写自己user_id对应行,管理员放开全量权限。

3.部门 / 组织权限隔离
OA、HR 系统:员工仅查看本部门数据,高管全量可见。

4.自动软删除过滤
USING(deleted_at IS NULL),查询永久屏蔽已删除数据。

5.合规隐私管控(HIPAA/GDPR)
医疗、金融系统,数据库层强制限制敏感病历、交易数据访问范围,满足审计要求。

五、RLS 核心优势

  • 安全兜底:控制下沉数据库,不依赖应用层代码,漏写 WHERE 也不会泄密;
  • 统一规则:一套策略作用于所有入口(API、后台、报表、存储过程);
  • 简化开发:ORM / 接口无需重复拼接租户过滤逻辑;
  • 易维护:权限规则改 SQL 策略即可,不用全量改业务代码;
  • 审计可控:所有数据访问强制走统一过滤规则,便于日志溯源。

六、缺点与生产注意事项

1. 性能损耗
每条查询附加过滤条件,大表必须给tenant_id/user_id建立索引;
复杂多表关联策略易触发全表扫描,避免嵌套 RLS 表(递归风险)。

2. 权限绕过风险(默认坑)
ENABLE RLS模式下表所有者、superuser 不受策略限制;多租户必须用FORCE ROW LEVEL SECURITY;
TRUNCATE、外键约束、表 DDL 操作不受 RLS 管控,需单独控制角色权限。

3. 连接池会话污染
连接池复用会话时,current_setting租户 ID 残留会导致串数据;
解决方案:每次请求结束重置会话变量,或使用连接池事务隔离。

4. 批量 / 统计查询限制
跨租户统计、全局报表需要单独创建超级只读角色,或单独开管理员策略。

七、补充:其他领域 RLS

  • BI 工具 RLS(Power BI/Tableau)
    报表层面行过滤,不同登录用户查看数据集不同行,仅作用可视化,不控制底层数据库;

  • 通信领域 RLS
    无线局域网 RLS(Radio Local System),极少和数据库 RLS 混淆。

八、与传统方案对比

方案 安全强度 维护成本 适用场景
应用层 WHERE 过滤 低(漏写即泄露) 高,全接口重复编码 简单单体、无多租户
视图封装 中,可绕过基表 中,多视图难管理 简单权限隔离
RLS 行级安全 极高,数据库强制拦截 低,统一策略 SaaS 多租户、隐私合规系统

九、MySQL 支持RLS吗

MySQL(社区版 5.7 / 8.0、RDS/Aurora MySQL 兼容版)没有原生 RLS(Row-Level Security)Amazon Web。MySQL Enterprise 企业版:同样不提供内置 RLS。

MySQL 三种主流 “模拟 RLS” 方案(多租户场景):

  • 方案 1:应用层强制拼接 tenant_id(最常用,生产首选)

  • 方案 2:可更新视图 + WITH CHECK OPTION(数据库层模拟)

  • 方案 3:存储过程封装所有 CRUD(强隔离但笨重)

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容