sql - 规范化表上 Postgres 中的行级安全性

标签 sql postgresql row-level-security

前提

In documentation ,行级安全性似乎很棒。根据我所阅读的内容,我现在可以停止创建这样的 View :

SELECT data.*
FROM data
JOIN user_data
ON data.id = user_data.data_id
AND user_data.role = CURRENT_ROLE

最重要的是,Postgres 对 view 进行了很好的分析,首先是索引扫描,然后是 user_data 表上的散列连接,这正是我们想要发生的事情因为它太快了。将其与我的 RLS 实现进行比较:

CREATE POLICY data_owner
ON data
FOR ALL
TO user
USING (
  (
    SELECT TRUE AS BOOL FROM (
      SELECT data_id FROM user_data WHERE user_role = CURRENT_USER
    ) AS user_data WHERE user_data.data_id = data.id
  ) = true
)
WITH CHECK (TRUE);

这个糟糕的策略执行 data 表中每一行的条件,而不是通过将查询范围限定到我们的 CURRENT_USER 可以访问,就像我们的 View 一样。需要明确的是,这意味着 select * from data 命中 data 表中的每一行

问题

如何使用内部 select 编写策略,它不会在目标表的每一 行上测试所说的 select。换句话说:如何让 RLS 在对结果运行实际查询之前在目标表上运行我的策略?

附注我让这个问题变得模糊不清,主要是因为 sqlfiddle还没到9.5。让我知道是否需要添加更多颜色或一些要点来解决我的问题。

最佳答案

如果您这样表述策略,PostgreSQL 可能会生成更好的计划:

...
USING (EXISTS
          (SELECT data_id
           FROM user_data
           WHERE user_data.data_id = data.id
             AND role = current_user
          )
      )

你应该有一个 (PRIMARY KEY?) 索引 ON user_data (role, data_id) 来加速嵌套循环连接。

但我认为将权限信息包含在 data 表本身中可能是一个更好的设计,也许使用 name[] 类型:

CREATE TABLE data(
   id integer PRIMARY KEY,
   val text,
   acl name[] NOT NULL
);

INSERT INTO data VALUES (1, 'one',   ARRAY[name 'laurenz', name 'advpg']);
INSERT INTO data VALUES (2, 'two',   ARRAY[name 'advpg']);
INSERT INTO data VALUES (3, 'three', ARRAY[name 'laurenz']);

然后你可以使用这样的策略:

CREATE POLICY data_owner ON data FOR ALL TO PUBLIC
   USING (acl @> ARRAY[current_user::name])
   WITH CHECK (TRUE);
ALTER TABLE data ENABLE ROW LEVEL SECURITY;
ALTER TABLE data FORCE ROW LEVEL SECURITY;

当我SELECT时,我只得到我有权限的行:

SELECT id, val FROM data;
 id |  val
----+-------
  1 | one
  3 | three
(2 rows)

您可以定义一个 GIN 索引来支持该条件:

CREATE INDEX ON data USING gin (acl _name_ops);

关于sql - 规范化表上 Postgres 中的行级安全性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42571569/

相关文章:

mysql - 计算每个项目和日期范围内的每个月库存中的项目数量 - mysql

azure - Azure Analysis Services 中的动态行级安全性

sql - PostgreSQL 行安全策略不适用于 CREATE POLICY FOR UPDATE WITH CHECK (false);

java - Hibernate hibernate.show_sql 在使用工作上传读取时未映射

sql - 报告服务 - 跨不同数据库使用相同的报告

node.js - 一个请求中的多个查询

sql - Postgres 中的递归 CTE

java - 从 Google map 获取坐标并将其插入 PostgreSQL

oracle - 在 Oracle VPD/RLS 中,如何防止恶意用户谓词泄露信息?

sql - 我将如何编写此 SQL 查询?