【问题标题】:Using PostgreSQL row level security (RLS) policies with current_setting() function将 PostgreSQL 行级安全 (RLS) 策略与 current_setting() 函数一起使用
【发布时间】:2021-04-09 19:05:36
【问题描述】:

我已将 RLS 策略应用于“用户”表,并希望仅检索带有 tenant_id=2 的记录:

CREATE TABLE "users" ("name" text UNIQUE NOT NULL, "tenant_id" int NOT NULL DEFAULT current_setting('app.current_tenant')::int);

--Enable Row Security Policies
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
ALTER TABLE users FORCE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation_policy ON users USING (tenant_id = current_setting('app.current_tenant')::int);

--Set "111" as the current tenant.
SET app.current_tenant TO 1;
INSERT INTO users VALUES ('admin');
INSERT INTO users VALUES ('bob');

--Set "222" as the current tenant.
SET app.current_tenant TO 2;
INSERT INTO users VALUES ('alice');

--Data output
SELECT * FROM users;

但我得到了结果中的所有用户:

name    tenant_id
admin   1
bob     1
alice   2

为什么会这样?

这是我所坚持的 dbFiddle: https://www.db-fiddle.com/f/iFktvVsDNYKggUNT2oDJBV/0

【问题讨论】:

  • 您使用哪个(数据库)用户来运行该 SELECT

标签: postgresql rls


【解决方案1】:

可以绕过行级安全性的原因有四个:

  • 用户是表的所有者。

    您可以使表所有者受到行级安全性

    ALTER TABLE users FORCE ROW LEVEL SECURITY;
    
  • 用户是超级用户。

  • 用户是用BYPASSRLS创建的。

  • 数据库参数row_security设置为off

请注意,使用带有占位符参数的行级安全性本质上是不安全的:如果攻击者可以发出 SQL 语句(例如,通过 SQL 注入),他们可以将值更改为他们喜欢的值。

【讨论】:

  • 确实,db-fiddle.com 用户是超级用户。
  • "使用带有占位符参数的 RLS 本质上是不安全的" - 有没有更好的方法将参数传递给策略,比如从连接字符串?
  • @Bergi 例如,您可以编写一个小的 C 扩展来定义一个只能设置一次的真实参数。
  • 这是一个可以正常工作的更新小提琴:db-fiddle.com/f/hGfeLXsUmmtpfCkbzWR6Ln/0
  • @Bergi 最好的办法是将它绑定到当前数据库用户。如果您在数据库中进行用户管理,最好使用 RLS。我认为了解安全隐患很重要。
猜你喜欢
  • 2021-05-19
  • 2020-07-21
  • 2018-06-22
  • 1970-01-01
  • 2022-01-03
  • 2021-11-14
  • 2022-07-07
  • 2020-10-25
  • 2021-03-31
相关资源
最近更新 更多