postgresql中创建security_barrier视图必须显式声明with (security_barrier = true),依赖所有调用函数标记为leakproof,且不能与rls或with check option混用;否则将降级为普通视图,失去防护能力。

PostgreSQL 中的 security_barrier 视图不是“开了就自动隔离”,它必须显式启用、依赖 LEAKPROOF 函数、且不能和 RLS 或 WITH CHECK OPTION 混用——否则看似安全,实则可能被绕过。
如何创建带 security_barrier 的视图
PostgreSQL 默认不启用安全屏障,哪怕你在视图里写了 WHERE 条件,普通视图仍允许谓词下推,攻击者可能通过低成本函数(如自定义 attack())触发提前执行,从而泄露本该被过滤的数据。
- 必须显式声明
WITH (security_barrier = true),例如:CREATE VIEW v_safe_users WITH (security_barrier = true) AS SELECT id, name, email FROM users WHERE status = 'active';
- 该语法仅在 PostgreSQL 9.5+ 支持;低于此版本无法使用
- 不能与
WITH CHECK OPTION共存,否则会报错ERROR: WITH CHECK OPTION is not supported for security barrier views - 创建后可用
\d+ v_safe_users查看输出中是否含security_barrier字样确认生效
为什么 LEAKPROOF 函数是硬性门槛
security_barrier 视图的安全性完全依赖底层函数是否标记为 LEAKPROOF。如果调用了非 LEAKPROOF 函数(比如自定义全文检索或脱敏函数),PostgreSQL 会拒绝将其用于安全屏障场景——要么建视图失败,要么静默降级为普通视图,失去保护能力。
PostgreSQL 18.4 官方 Ubuntu 安装包现已发布,这是目前最新的稳定版本。推荐通过官方 APT 仓库安装:先执行 sudo apt update 更新索引,再运行 sudo apt install postgresql-18 即可完成部署。新版本引入了异步 I/O 子系统,在顺序扫描与 VACUUM 场景下性能提升显著,同时支持 UUID v7 原生生成函数与虚拟生成列。
- 检查函数是否 LEAKPROOF:
SELECT proname, proleakproof FROM pg_proc WHERE proname IN ('to_tsvector', 'mask_phone'); - 内置函数如
length()、upper()通常是 LEAKPROOF;但to_tsvector('english', ...)默认不是 - 重建自定义函数时需显式加
LEAKPROOF(仅超级用户可设):CREATE OR REPLACE FUNCTION mask_phone(text) RETURNS text AS $$...$$ LANGUAGE sql LEAKPROOF;
- 非 LEAKPROOF 函数可能通过
RAISE NOTICE、异常消息、执行时间差等方式泄露中间结果
与 RLS 混用时的执行顺序陷阱
当视图底层表已启用行级安全策略(RLS),而你又建了 security_barrier = true 视图,两者不会自动协同——执行顺序取决于视图的 security definer/invoker 模式,容易导致过滤被跳过或重复。
- 若视图是
SECURITY DEFINER(默认),RLS 策略按 owner 身份执行,可能在视图过滤前就截断数据,导致用户看到空结果 - 若设为
SECURITY INVOKER,RLS 按调用者身份检查,此时security_barrier仍有效,但前提是所有函数都 LEAKPROOF - 测试时务必用目标普通用户连接,而非
postgres或视图 owner,否则 RLS 和安全屏障都可能被跳过 - 用
EXPLAIN (VERBOSE) SELECT * FROM v_safe_users;查执行计划:确认没有出现Row Security Policy干预,且视图的 WHERE 条件明确出现在最外层过滤位置
真正能防住什么、防不住什么
security_barrier 视图只解决“谓词下推绕过过滤”的问题,它不是访问控制层,也不替代 RLS 或角色权限。
- 它能防:恶意用户构造
WHERE false OR attack(id)类查询,迫使数据库提前调用函数并泄露敏感中间值 - 它不能防:用户直接查底层基表(只要他有 SELECT 权限)、绕过视图走 JOIN 或子查询、或利用应用层拼接 SQL 注入
- DBA 无法通过
\dp+或pg_policies审计这类视图的实际防护效果——它的安全性完全藏在函数属性和执行计划里 - 最易被忽略的一点:即使视图定义正确,只要调用链中任一函数未标记 LEAKPROOF,整个屏障就形同虚设










