8.1.4 等安全发布用户指南
PostgreSQL 全球开发组今天发布了所有活动分支的更新。这些更新修复了一个严重的 SQL 注入安全漏洞。建议所有运行暴露给不受信任用户或网络的系统的 PostgreSQL 用户尽快升级。请注意,完整的修复可能还需要升级客户端和驱动程序库。
为什么要这样做?
几周前,我们日本的开发者社区成员联系我们,告知了使用 PHP 在远东字符编码(如 SJIS)中针对 PostgreSQL 的 SQL 注入漏洞。似乎一个聪明的攻击者可以利用对 PostgreSQL 中多字节编码和字符串转义方式的了解,绕过所有常用客户端安全措施,偷偷地注入 SQL 字符串。随后的调查表明,相关攻击会在所有多字节编码中起作用,特别是全球广泛使用的 UTF8。
有关此漏洞工作原理的更多技术信息,请参阅下面的“漏洞技术细节”。
这对我有何意义?
首先,这意味着如果您运行的 PostgreSQL 服务器暴露给不受信任的输入……无论是来自网络,还是来自注重安全性的应用程序中的内部用户……那么您需要尽快升级 PostgreSQL。
除了 PostgreSQL 本身之外,本周还将升级许多 PostgreSQL 驱动程序(Java、PHP、Perl、Ruby 等)。您需要同时升级它们。不幸的是,一些旧版应用程序也需要修复。服务器更改将帮助您找出这些应用程序,但它们本身不会修复代码。这意味着您需要在升级生产软件之前在新的版本上测试您的应用程序。
重要的是要了解,所解决的根本问题出在客户端:需要“转义”字符串值以便将其插入 SQL 查询的客户端必须在知道其使用的字符集编码的情况下进行转义。依赖于库或驱动程序函数进行转义的应用程序在库或驱动程序升级后将是安全的。自己进行“自制”转义的应用程序(例如,通过使用正则表达式替换来加倍引号和反斜杠)如果在任何多字节字符集编码中使用,则存在严重风险。
一个有风险的应用程序示例是使用 addslashes() 或 magic_quotes 的 PHP 程序。我们注意到,PHP 组从 4.0 版本开始弃用这些工具。一些还没有更新驱动程序的其他编程语言也可能存在漏洞。如有疑问,请测试或联系您的数据库驱动程序项目。
由于不可能立即修复所有有风险的应用程序,因此我们在 PostgreSQL 服务器中添加了更改,使其拒绝可能被 SQL 注入攻击破坏的查询。使用更新后的服务器,您可以确保此类攻击不会成功执行不需要的 SQL 命令——但攻击会导致您的应用程序从服务器收到错误,应用程序可能能够优雅地处理,也可能无法处理。因此,您需要尽快确保修复任何应用程序编码缺陷。
具体发生了哪些改变?
为了彻底堵住这个安全漏洞,我们不得不对客户端和服务器进行更改。这些更改中的大多数也已移植到 8.0、7.4 和 7.3 版本。
服务器的更改
在 PostgreSQL 服务器中进行了两项更改,使其拒绝可能被破坏的查询
1) 当客户端使用多字节编码时,服务器将拒绝包含无效编码的多字节字符的字符串。虽然 PostgreSQL 一直在朝着这个方向发展,但现在这些检查已移植到所有支持的版本,统一应用于所有编码,并且无法禁用。这可能会导致以前允许字符串输入中存在“垃圾字符”的应用程序出现问题。如果您需要存储任何已识别编码之外的数据,建议在连接的两端使用 SQL_ASCII 编码。
2) 当客户端使用“仅客户端”编码(SJIS、BIG5、GBK、GB18030 或 UHC)时,服务器还会拒绝使用“\’”在 SQL 字符串字面量中表示单引号。这种历史用法在一段时间内已被弃用,取而代之的是 SQL 标准表示法“”(两个单引号)。但是,它仍然非常常见,此更改无疑会导致一些应用程序出现问题。因此,我们添加了一个服务器参数“backslash_quote”,可以设置它来控制服务器的严格程度:
* backslash_quote = on : Allow \' always (old behavior; INSECURE * backslash_quote = off : Reject \' always * backslash_quote = safe_encoding : Allow \' if client_encoding is safe
“safe_encoding”是新的默认值,因为许多实际应用程序使用服务器安全编码,因此无需立即强制更改。“on”可以在绝对必要时用于应用程序兼容性,但在使用暴露给不受信任输入的客户端时不安全。
客户端和 libpq 更改
如果您的应用程序使用 libpq(核心 PostgreSQL 发行版中包含的 C 语言客户端库),那么重要的更改在 PQescapeString 和 PQescapeBytea 中,这是该库提供的用于转义字符串的两个例程。如果您的代码一次只使用一个 PostgreSQL 数据库连接,那么更新后的 PQescapeString 和 PQescapeBytea 版本将对您有效。如果您的应用程序同时使用多个连接,则应调整您的代码以使用新的函数 PQescapeStringConn 和 PQescapeByteaConn,这些函数确保它们针对特定数据库连接正确地进行转义。
如果您的代码正在“手动”进行转义,例如通过加倍引号和反斜杠,那么您真的需要修复它以使用库例程。如果您完全避免了转义的需要,通过将变量字符串作为非行参数发送,那么您已经为自己省去了很多麻烦,可以不再担心。
大多数其他客户端库都有类似的工具来处理将变量字符串插入 SQL 查询中。无论您使用什么,您都需要确保插入的字符串由正确更新的函数处理。