PostgreSQL 教程: 防范 SQL 注入攻击

九月 5, 2024

摘要:在本教程中,您将学习如何保护 PostgreSQL 免受 SQL 注入攻击。

目录

SQL 注入是一种代码注入技术,用于通过在输入字段中插入恶意 SQL 语句,来攻击数据驱动的应用程序。对于 PostgreSQL 这样一个强大且功能丰富的数据库,确保防止 SQL 注入的安全性,对于维护数据完整性和防止未经授权的访问至关重要。

预备语句和参数化查询

参数化查询是在代码中进行的查询,这样值将与 SQL 语句一起传入,语句中带有占位符的值,表示将插入所提供的值的位置。一个预备语句是对准备接受参数的预编译查询的引用。

防止 SQL 注入攻击的最有效方法是,以参数化查询来使用预备语句。此方法涉及创建 SQL 查询模板,并将其与参数发送到数据库,数据库引擎本身会以安全的方式来替换参数。

PREPARE plan (int, text) AS
  INSERT INTO employees (id, name) VALUES ($1, $2);

EXECUTE plan (1, 'John Doe');

这种方法可确保数据库将值视为数据,而不是 SQL 命令的一部分,从而防止攻击者注入恶意代码。

存储过程

存储过程是一系列指令,用于存储应用程序经常使用的一系列查询。存储过程提供了另一层安全性。它们将 SQL 代码封装在数据库中,并允许设置执行的权限,从而限制谁可以在数据库中运行哪些内容。

CREATE OR REPLACE FUNCTION add_employee(employee_id int, employee_name text)
RETURNS void AS $$
BEGIN
    INSERT INTO employees (id, name) VALUES (employee_id, employee_name);
END;
$$ LANGUAGE plpgsql;

通过使用存储过程,您可以最大限度地减少 SQL 注入的影响范围,因为可以在存储过程中安全地处理输入参数。

如果使用得当,存储过程还有其他好处。使用它们可以提高性能,因为它们只要编译一次,然后以可执行的形式存储。这种可执行的代码会被缓存,从而降低内存需求。存储过程还支持代码的可重用、更轻松的维护和更高的安全性。存储过程可以控制执行的流程和活动,从而保护数据库对象,并简化安全性。攻击者更难将命令插入到存储过程内的 SQL 语句中。

输入验证

在客户端和服务端验证用户输入,可以大大降低 SQL 注入的风险。确保每个用户输入都符合预期的模式和约束,然后再由您的应用程序处理,或传递到 PostgreSQL 数据库。

除了特定于编程语言的输入验证之外,在设计数据库时使用约束,特别是检查约束,也可以作为抵御 SQL 注入的另一道防线。PostgreSQL 文档中关于 check 约束的描述,“check 约束是最通用的约束类型。它允许您指定特定列中的值必须满足一个布尔(真值)表达式。例如,要求产品价格为正之,您可以使用:”

/* Adding a check that requires positive product prices */
CREATE TABLE products (
    productnum integer,
    name text,
    price numeric CHECK (price > 0)
);

这也可以在现有数据库上使用ALTER TABLE来实现。子命令(如ADD table_constraintALTER CONSTRAINTDROP CONSTRAINT)也可用来实现此目的。

转义所有用户输入

如果必须在 SQL 语句中包含用户输入,请确保正确地转义输入。PostgreSQL 提供了 quote_literalquote_nullable 等函数,这些函数可以帮助转义合并到 SQL 命令中的字符串。

SELECT * FROM accounts WHERE username = quote_literal(user_input);

此外,PostgreSQL 的 C 库(libpq)内置了转义函数,可以与命令执行函数结合使用。PQescapeLiteral 可用于转义字符串,以包含在 SQL 命令中。正如官方 libpq 文档中所述,“这在 SQL 命令中将数据值作为文本常量插入时非常有用。某些字符(例如引号和反斜杠)必须进行转义,以防止 SQL 解析器对它们进行特殊解释。”。该库也包括了其他有用的转义函数,例如PQescapeByteaConn(用于转义二进制数据)和PQescapeIdentifier(用于转义用作 SQL 标识符的字符串,例如表名)。与输入验证一样,最佳做法是使用这些类型的内置函数,而不是 “开发你自己的”。

但是,此方法不如使用预编译语句或存储过程安全,应谨慎使用。

最小权限原则

最小权限是一种安全原则,它主张仅授予用户或进程执行其任务所需的最低级别的访问权限。应用最小权限原则来限制 SQL 的影响,涉及确保数据库用户和应用程序,仅具有执行 SQL 查询和访问数据所需的权限。这可以通过为数据库用户分配其特定任务所需的最低必要权限来实现。例如,如果用户或服务账户只需要从某些表中读取数据,则授予他们对这些特定表的只读访问权限,而不是对整个数据库的完全读写访问权限,可以通过限制或阻止攻击者修改或删除数据的能力,来减少 SQL 注入攻击的冲击范围。

遵守最小权限原则对于保护数据库至关重要。确保应用程序数据库用户仅具有执行其任务所需的权限。这最大限度地减少了发生注入攻击时的潜在损害。

最小权限也可以与前面提到的存储过程结合使用。通过为常见数据库操作定义特定的存储过程,并仅授予对这些存储过程的执行权限,利用存储过程来封装数据库操作,并实施访问控制,从而限制对底层表的直接访问,从而防止 SQL 注入漏洞。

定期更新和修补

使用最新的安全补丁,使 PostgreSQL 保持更新至关重要,因为漏洞会随着时间的推移而被发现和修复。定期更新有助于防范已知的攻击手段。

结论

总之,保护 PostgreSQL 免受 SQL 注入的影响,需要组合各种最佳实践,包括预备语句、存储过程、输入验证、合理转义用户输入、遵守最小权限原则以及保持软件更新。