不能。postgresql触发器无法实现严格的行级权限控制,因其不响应select,无法拦截读操作;仅能在insert/update/delete中配合应用层传参(如set local)校验归属,且易被join、子查询等绕过,真正读写全链路控制须用rls。

不能。PostgreSQL 中的 SQL 触发器无法实现“严格的行级权限控制”,因为触发器不响应 SELECT,而读权限控制恰恰是最关键、最常被绕过的环节。
为什么 BEFORE INSERT/UPDATE 触发器拦不住越权读取
用户执行 SELECT * FROM orders WHERE id = 123 时,任何触发器都不会被调用——标准 SQL 没有 BEFORE SELECT 或 AFTER SELECT 语法,PostgreSQL 和所有主流数据库都不支持。这意味着:
- 即使你在 orders 表上绑定了严格校验的 BEFORE UPDATE 触发器,用户仍可直接查出所有行
- 攻击者可通过 JOIN users ON orders.owner_id = users.id 或子查询绕过写入层校验
- TRUNCATE、COPY FROM、UNION ALL 等操作也完全不受触发器约束
哪些场景下触发器能起作用(且必须配合应用传参)
触发器只在你明确绑定的 DML 操作上生效,且必须依赖应用层主动注入上下文,否则校验无意义:
-
SET LOCAL app.user_id = 'u789'必须由应用在每个事务开始时显式执行,否则current_setting('app.user_id', true)返回NULL -
BEFORE INSERT可校验NEW.owner_id = current_setting('app.user_id', true),防止伪造归属 -
BEFORE UPDATE需同时检查OLD.owner_id = current_setting('app.user_id', true)(确保原属自己)和NEW.owner_id是否被篡改 -
BEFORE DELETE只需验证OLD.owner_id匹配,但无法阻止DELETE FROM orders WHERE tenant_id = 'other_tenant'这类批量误删
常见错误:把触发器当 RLS 用
有人写完触发器就以为安全了,结果上线后发现数据泄露,典型错误包括:
- 在
AFTER INSERT里抛异常——此时数据已写入,事务可能已部分提交,造成不一致 - 触发器里查权限表(如
SELECT can_view FROM user_perms WHERE user_id = ...)——高并发下锁住权限表,拖垮整个库 - 用
CURRENT_USER判断业务身份——它返回的是数据库角色名(如app_rw),不是真实用户 ID - 没禁用超级用户的 RLS 绕过行为,或忘了加
ALTER TABLE ... FORCE ROW LEVEL SECURITY
真正需要“严格行级权限”的地方,必须用 CREATE POLICY 配合 ENABLE ROW LEVEL SECURITY;触发器只适合补 RLS 做不到的强业务规则,比如“金额变更不得超过上一版本的 15%”。混淆这两者的边界,是生产环境权限漏洞最常发生的根源。










