使用受信语言扩展通过钩子增强 PostgreSQL 数据库安全性 数据库博客
  • 24

提升 PostgreSQL 数据库安全性:使用 Trusted Language 扩展的 Hook

关键要点

在这篇文章中,我们将介绍如何通过 PostgreSQL 的 Trusted Language 扩展TLE增强数据库的安全性,特别是在用户认证方面。TLE 允许您使用钩子函数添加密码复杂性检查和用户锁定功能,从而有效提高数据库的安全性。

PostgreSQL 具备使用本地凭证进行用户名和密码的身份验证功能,但缺乏强制实施特定密码复杂性及其他高级身份验证策略的能力,通常需要借助外部身份服务,如 LDAP 或 Kerberos。通过使用 Trusted Language ExtensionsTLE,一个开源开发工具包,用户可以创建和打包扩展,目前可以通过 clientauth 钩子来添加上述缺失的功能。支持的信任语言包括 PL/pgSQL、PL/v8 和 PL/Rust。

在 TLE 首次发布时,已支持密码检查钩子,您可以通过该钩子构建自定义的密码复杂度检查函数并将其包装在扩展中。本文引用的 TLE 版本为 pgtle v140,此版本可在 Amazon Relational Database Service (Amazon RDS) for PostgreSQL 162R2、156R2、1411R2 及更高版本的数据库实例上使用,新增支持“客户端身份验证”钩子,在用户尝试身份验证后运行,并改进现有的密码检查钩子。

本文将为您详细介绍 TLE 中钩子的增强功能,并展示如何创建客户端身份验证钩子的示例。

PostgreSQL 中的钩子是什么?

钩子是事件驱动的函数,在不同的数据库操作中用于修改查询的执行方式以及 PostgreSQL 数据库的反应。钩子有多种类型,包括一般钩子、规划器钩子、执行器钩子等。如今,许多 PostgreSQL 扩展都在使用钩子。例如,pgstatstatements 扩展用于跟踪查询的性能统计信息,使用 ExecutorStarthook、ExecutorRunhook 和 ExecutorFinishhook 来获取查询的运行时信息。

让我们来看看 TLE 支持的最新钩子与功能。

支持集群范围的 passcheck 钩子

TLE 支持 passcheck 钩子,允许您构建满足团队密码合规性要求的钩子。您可以创建一个自定义函数,并为用户提供的密码提供额外的验证规则。有关如何构建 TLE 来验证用户密码的详细信息,请参见 关于 Amazon Aurora 和 Amazon RDS 的 Trusted Language Extensions 的新功能。默认情况下,passcheck 钩子仅在注册的当前数据库中运行。您需要在每个希望使用此功能的数据库中显式注册该钩子。

在 pgtle 版本 140 及更高版本中,您可以设置参数 pgtlepasscheckdbname 来控制在单个数据库中 passcheck 钩子的集群范围设置。当该参数被设置时,指定数据库中的注册函数将在集群内的所有数据库中运行。然而,passcheck 函数以数据库超级用户身份运行在 Amazon RDS 中为 rdssuperuser,因此我们在定义函数时需考虑以数据库超级用户特权执行的代码的安全性。在使用 Amazon RDS 时,您可以使用 AWS 管理控制台 或 AWS 命令行工具AWS CLI启用 passcheck 钩子,以便其在所有数据库中生效。要启用 passcheck,您需将 pgtleenablepasswordcheck 设置为 on 或 require。可以使用以下命令通过 AWS CLI 启用该参数:

bashaws rds modifydbparametergroup region useast1 dbparametergroupname pgtlepg parameters ParameterName=pgtlepasscheckdbname ParameterValue=nameofdatabaseApplyMethod=immediate

支持客户端身份验证钩子

TLE 现在还支持客户端身份验证钩子,它为您提供了对身份验证过程的额外控制。clientauth 钩子可用于跟踪身份验证失败的情况,并在多次失败的登录尝试后锁定用户。这有助于缓解各种攻击,例如字典攻击,黑客会运行密码哈希文件,查找字典中常用的密码。您可以使用以下命令在您的 RDS PostgreSQL 实例中启用客户端身份验证钩子:

bashaws rds modifydbparametergroup region useast1 dbparametergroupname pgtlepg parameters ParameterName=pgtleenableclientauthParameterValue=onApplyMethod=immediate

虽然 pgtleenableclientauth 是动态参数,但启用它确实需要重启。让我们重启 DB 集群以启用此参数:

bashaws rds rebootdbinstance region useast1 dbinstanceidentifier pgtleisfun

要确认钩子已启用,您可以在终端中运行以下命令:

bashSHOW pgtleenableclientauth

此时应返回以下输出:

pgtleenableclientauth

使用受信语言扩展通过钩子增强 PostgreSQL 数据库安全性 数据库博客

on

以下代码示例显示如何编写一个简单的函数,在特定的失败登录尝试次数后锁定用户在此示例中为五次:

sqlCREATE EXTENSION IF NOT EXISTS pgtle

SELECT pgtleinstallextension( clientlockout 10 五次连续失败登录后锁定用户pgtle CREATE SCHEMA clientlockout

CREATE TABLE clientlockoutfailedattempts (    username           text    PRIMARY KEY    numfailedattempts integer)CREATE FUNCTION clientlockouthookfunction(port pgtleclientauthportsubset status integer)RETURNS void AS     DECLARE        numattempts integer    BEGIN         获取此用户的连续失败尝试次数        SELECT COALESCE(numfailedattempts 0) FROM clientlockoutfailedattempts            WHERE username = portusername            INTO numattempts         如果至少有 5 次连续失败尝试,则拒绝        IF numattempts gt= 5 THEN            RAISE EXCEPTION  已连续失败 5 次, 请联系数据库管理员 portusername        END IF         如果密码错误,增加计数        IF status = 1 THEN            INSERT INTO clientlockoutfailedattempts (username numfailedattempts)                VALUES (portusername 1)                ON CONFLICT (username) DO UPDATE SET numfailedattempts = clientlockoutfailedattemptsnumfailedattempts  1        END IF         如果密码正确,重置计数为 0        IF status = 0 THEN            INSERT INTO clientlockoutfailedattempts (username numfailedattempts)                VALUES (portusername 0)                ON CONFLICT (username) DO UPDATE SET numfailedattempts = 0        END IF    END LANGUAGE plpgsql 允许扩展所有者将任何用户的密码尝试次数重置为 0CREATE FUNCTION clientlockoutresetattempts(targetusername text)RETURNS void AS     BEGIN        INSERT INTO clientlockoutfailedattempts (username numfailedattempts)            VALUES (targetusername 0)            ON CONFLICT (username) DO UPDATE SET numfailedattempts = 0    END LANGUAGE plpgsqlSELECT pgtleregisterfeature(clientlockouthookfunction clientauth)REVOKE ALL ON SCHEMA clientlockout FROM PUBLIC

pgtle)

CREATE EXTENSION clientlockout

现在钩子已激活。如果我们五次输入错误密码,连接将失败:

bash psql d postgres U tleuserPassword for user testpsql error 连接到服务器时出错 /tmp/sPGSQL5432 FATAL tleuser 已连续失败 5 次,请联系数据库管理员

要解锁用户,请使用此命令:

sqlpostgres=# select clientlockoutresetattempts(tleuser) resetattempts

(1 row)

pixiv手机版梯子

请注意,如果数据库客户端将 sslmode 参数设置为 allow 或 prefer,如果第一次连接失败,客户端将自动尝试重新连接。这将触发 clientauth 函数两次,可能会导致用户比预期更早被锁定。

清理工作

完成以下步骤以清理您在数据库中创建的扩展:

要禁用钩子,将 pgtleenableclientauth 的值设置为 off:

bashaws rds modifydbparametergroup region useast1 dbparametergroupname pgtlepg parameters ParameterName=pgtleenableclientauth ParameterValue=offApplyMethod=immediate

然后,删除扩展 clientlockout:

sqlDROP EXTENSION clientlockout

最后,卸载扩展:

sqlSELECT pgtleuninstallextension(clientlockout)

结论

在本文中,我们回顾了 TLE 中钩子的增强功能,并演示了如何创建客户端身份验证钩子。尽管 PostgreSQL 核心功能具备通过本地凭证进行用户身份验证的能力,但缺乏强制实施特定密码复杂性等高级身份验证策略,通常需要依赖外部身份服务。使用 TLE 提升 PostgreSQL 数据库钩子,用户可以在不依赖外部提供者的情况下实现这些类型的身份验证策略,正如本文所示。

欢迎您在评论区留下意见和反馈。

关于作者

彼得塞伦塔诺 是一名资深解决方案架构师,工作于亚马逊网络服务,专注于托管 PostgreSQL。他与 AWS 客户合作,设计可扩展、安全、性能优异且强健的云数据库架构。

苏克普里特考尔贝迪 是一名高级数据库专员解决方案架构师,专注于 AWS 的 Amazon RDS/Aurora PostgreSQL 引擎。她帮助客户在 AWS 平台上创新,构建高可用性、可扩展及安全的数据库架构。