Laurenz Albe:函数何时是防泄漏的?

Laurenz Albe:函数何时是防泄漏的?

💡 原文英文,约2100词,阅读约需8分钟。
📝

内容提要

本文探讨PostgreSQL行级安全(RLS)的性能与安全问题。RLS通过自动附加条件隐藏数据,为提升性能引入LEAKPROOF函数标记,允许其在安全条件前执行。作者指出EXPLAIN ANALYZE等隐蔽信道可能泄露隐藏数据,而严格标记LEAKPROOF会拖累性能,建议仅当参数可触发泄露时才拒绝标记,并质疑是否应限制EXPLAIN权限。

🔎

延伸解读

RLS 的隐蔽信道风险

文章指出,即使启用了行级安全,攻击者仍可能通过 EXPLAIN 或查询运行时间等隐蔽信道推断隐藏数据。例如,EXPLAIN 输出中的“Rows Removed by Filter”会直接暴露被过滤掉的行数,从而泄露信息。这意味着 RLS 并非绝对安全,不能完全防止有权限运行任意 SQL 的用户进行推断攻击。

LEAKPROOF 标记的权衡

将函数标记为 LEAKPROOF 可以让优化器在安全条件之前执行它,从而提升性能,但若标记不当,可能通过错误消息等侧信道泄露参数信息。PostgreSQL 目前仅将少数系统函数标记为 LEAKPROOF,导致许多 RLS 查询性能不佳。作者建议仅当参数能触发泄露时才拒绝标记,以平衡安全与性能。

EXPLAIN 权限限制的争议

作者曾提议在涉及 RLS 时限制 EXPLAIN (ANALYZE) 仅对 pg_read_all_stats 角色可用,但遭到反对。反对者认为存在其他绕过方式,且限制 EXPLAIN 会影响查询调优,甚至可能促使更多用户申请该角色,反而降低安全性。作者最终撤回补丁,但对此仍有保留。

RLS 的适用场景

基于上述分析,作者认为不应将 RLS 视为对可运行任意 SQL 的用户的保护。更安全的用法是在应用程序中控制 SQL 语句,用户只能影响参数值。这样,即使存在隐蔽信道,攻击面也大大减小。RLS 更适合多租户应用等受控环境。

❓

Q&A

PostgreSQL 中 LEAKPROOF 函数标记的作用是什么?

LEAKPROOF 标记表示函数没有副作用,除了返回值外不泄露任何关于参数的信息。被标记为 LEAKPROOF 的函数和操作符可以在安全策略条件之前执行,从而提升查询性能。

为什么 PostgreSQL 默认只将少数函数标记为 LEAKPROOF?

因为安全与性能是经典的对立面。如果随意将函数标记为 LEAKPROOF,优化器可能选择更快的执行计划,但会带来安全风险。PostgreSQL 传统上倾向于谨慎,例如在标准 v18 安装中只有 345 个 LEAKPROOF 函数,且大多是基础类型的比较函数。

EXPLAIN ANALYZE 如何可能泄露行级安全隐藏的数据?

EXPLAIN ANALYZE 的输出可能包含“Rows Removed by Filter”等信息,从而暴露被过滤掉的行数或数据分布。例如,即使使用了 LEAKPROOF 操作符,EXPLAIN 仍可能显示存在某个账户,从而泄露隐藏数据。

作者对限制 EXPLAIN (ANALYZE) 权限的提议有何看法?

作者曾提议将 EXPLAIN (ANALYZE) 限制给 pg_read_all_stats 角色成员,但遭到反对。反对理由包括:存在其他绕过行级安全的方法,限制 EXPLAIN 可能让用户误以为行级安全更安全,且可能影响性能调优。作者最终撤回了补丁,但仍对“因为还有其他漏洞就不堵这个漏洞”的论点持保留态度。

作者认为行级安全应该用在什么场景下?

作者认为不应将行级安全视为对能运行任意 SQL 语句的用户的保护。安全的使用方式是在应用程序上下文中使用,由应用程序控制 SQL 语句,用户只能影响参数值。

作者对 LEAKPROOF 标记中内存不足错误泄露信息的问题有何建议?

作者认为,只有当通过向 SQL 语句提供参数值(在应用程序控制下)能触发泄露信息的错误时,才应拒绝标记 LEAKPROOF。对于内存不足错误等无法通过恶意构造值触发的错误,不应因此拒绝 LEAKPROOF,否则会严重影响行级安全的性能。

🏷️

标签

➡️

继续阅读