Postgres密码加密-不要泄露凭证信息哦

文摘   科技   2024-08-04 06:02   德国  


原文来自Postgresweekly January 17, 2024[1] 的好文推荐。稍加整理,以享大家。

目录

  • 背景[2]
  • Password Encryption (i.e. "hashing")
  • PostgreSQL Password Encryption - MD5[3]
  • PostgreSQL Password Encryption - SCRAM-SHA-256[4]
  • CREATE USER / ALTER USER[5]
  • Libraries
    • C - libpq[6]
    • Java - PostgreSQL JDBC Driver (PGJDBC)[7]
    • node.js - pg-password-util[8]
    • python - psycopg's encrypt_password[9]
  • Password Generation[10]
  • Final Thoughts[11]

背景

“跳舞吧,就像没人在看一样。像每个人一样加密。”

-- Adrian Lamo

创建一个用户来访问PostgreSQL数据库的最简单的方法是这样的:

CREATE USER app PASSWORD 't0pSecret!'

但是,该SQL的文本将被发送到远程数据库服务器执行。这意味着密码的明文本身被发送到数据库。如果启用了语句日志记录,服务器日志中将显示以下内容:

2024-01-14 19:09:09.064 UTC [75] LOG:  statement: CREATE USER app PASSWORD 't0pSecret!';

如果在你和数据库服务器之间有一个连接池或代理,那么它最终也可能出现在这些日志中。但是实际上,我们可以做得更好。更好的!

密码加密(如hash)

PostgreSQL文档将这个主题称为“密码加密”。实际上,正在执行的操作是HASH和HMAC的一种形式。

服务器不需要知道数据库用户密码的确切文本。它只需要知道您提供的凭据是否与授权访问该用户的凭据相匹配。

密码Hash是执行这种计算的一种方法,它允许服务器只存储单向Hash函数的结果。然后,服务器可以检查对连接尝试中提供的凭据应用密码Hash操作的结果是否与预期的密码Hash匹配。

MD5密码加密

直到PostgreSQL v10,只有一个内置的加密选项来处理密码:md5

使用md5密码加密,服务器将md5(密码||用户名)存储在它的内部pg_shadow系统catalog当中(想想/etc/shadow,但用于数据库密码)。

本文中的hash操作使用下边的表达式:

MD5( ...) = 仅带一个参数的md5函数

|| = 二元操作,用于对两个原始字节流进行拼接操作

于是: 'foo' || 'bar' = 'foobar' and MD5('test') = '098f6bcd4621d373cade4e832627b4f6'

在PostgreSQL应用协议的认证步骤中,服务器随机选择一个加盐,并要求认证客户端计算:MD5(MD5(password || username) || salt))。

随机加盐可以防止先前连接中的值在以后的连接尝试中被重用(也称为重放攻击)。不幸的是,在有线协议中,盐的大小只有四个字节,所以它不是特别有效。如果有足够的连接尝试,假设没有传输级加密(TLS),那么攻击者有可能收集所有可能的身份验证响应。

SCRAM-SHA-256密码加密

从PostgreSQL v10开始,添加了一个新选项,并将其作为处理密码的默认选项:sram - sha -256

SCRAM是加盐挑战响应认证机制[12]的缩写。

它可以与各种散列(Hash)算法一起使用。PostgreSQL实现只支持SHA-256。

与md5加密相比,SCRAM具有许多优点:

  • 采用现代Hash函数 (SHA-256)
  • 更大的加盐大小 (默认为16字节)
  • key stretching[13] (默认为 4096 轮), 键延展性好
  • 能向客户端证明服务器端知道客户端的凭证(客户端也同时能认证服务器端!)

有了scam-sha-256,就没有理由在现代PostgreSQL服务器上使用md5身份验证了。

CREATE USER / ALTER USER

创建用户的PostgreSQL SQL命令,CREATE user…,接受……PASSWORD 'literal-value-goes-here'子句,用于指定密码。ALTER USER…Command的操作类似。

服务器检查新密码值,并确定它是否已经加密。如果没有,服务器将使用连接的默认加密方法(SHOW password_encryption查看默认加密方法)对其进行加密。

如果新密码的值以md5开头,那么服务器假定它是一个已经使用md5方案加密的密码。

如果新密码的值以sram-sha-256$ 开头,那么服务器认为它是一个已经使用sram-sha-256方案加密的密码。

因此,以下命令将指示PostgreSQL服务器使用连接的默认密码加密来加密密码:

CREATE USER alice PASSWORD 'abcd'

然而,这将被视为已经加密的md5密码:

CREATE USER alice PASSWORD 'md5fb592cb4152e2aacaaf452714d283f7e'

这将被视为已经加密的sam-sha-256密码:

CREATE USER alice PASSWORD 'SCRAM-SHA-256$4096:jHhJMplyRcr1io3v3YwabQ==$WNwkp8PFet/L8UUtFBEa7Sn8xSofpPZ4klcfuB0w6Yk=:Oqnfxd3FhyYTALxW+YeU/yVAzxKT+ho08E+hE/'

在这三种情况下,用户都可以使用相同的密码abcd登录,但是在第一种情况下,用户的密码可能在命令执行期间被登录而泄露。

同样的更新可以通过ALTER USER…命令:

-- Have the server encrypt the password ... BAD
ALTER USER alice PASSWORD 'abcd';

-- Provide an md5 encrypted password ... BETTER (but not great)
CREATE USER alice PASSWORD 'md5fb592cb4152e2aacaaf452714d283f7e'

-- Provide a SCRAM-SHA-256 encrypted password ... BEST (really this is only one you should be using)
CREATE USER alice PASSWORD 'SCRAM-SHA-256$4096:jHhJMplyRcr1io3v3YwabQ==$WNwkp8PFet/L8UUtFBEa7Sn8xSofpPZ4klcfuB0w6Yk=:Oqnfxd3FhyYTALxW+YeU/yVAzxKT+ho08E+hE/'

没有理由向服务器提供明文密码。服务器甚至不保存密码的明文。它会立即加密(使用当前的password_encryption选项)并保存加密后的值:

postgres=# ALTER USER alice PASSWORD 'abcd';
ALTER ROLE
postgres=# SELECT passwd FROM pg_shadow WHERE usename = 'alice';
passwd ------------------------------------------------------------------------------------------------------------
SCRAM-SHA-256$4096:awluLTEXFg1qnYqxpmRNkQ==$FPHOxeG4sUCa+vy6W83VMHaXr3rSRq2QVfkvmAMad2A=:g9oXk/UT6fF+N8z5aFIQpRvLfm8Yz13ZEjdhrWhY2/0=
(1 row)

在最好的情况下,密码不会泄露到某些日志文件中。但你永远不会真正知道,对吧?

相关库

由于创建用户和更新他们的密码是一项非常常见的任务,因此它被添加到许多PostgreSQL库中。这些库中的帮助程序处理密码加密,以便在SQL命令中使用密码而不暴露其明文。

C - libpq

https://www.postgresql.org/docs/current/libpq-misc.html#LIBPQ-PQENCRYPTPASSWORDCONN

libpq C库是PostgreSQL核心的一部分,也是许多用户工具和其他驱动程序的基础。它提供了一个函数' PQencryptPasswordConn(…)'[14],该函数将使用所提供连接的默认值加密密码。

Java - PostgreSQL JDBC Driver (PGJDBC)

https://github.com/pgjdbc/pgjdbc/blob/master/pgjdbc/src/main/java/org/postgresql/util/PasswordUtil.java

一个辅助类PasswordUtil最近被添加到PostgreSQL Java数据库驱动程序PGJDBC中。该类中的方法允许对加密类型和内部参数(例如SCRAM迭代次数或盐大小)进行细粒度控制。还有一些方法可以生成ALTER USER…用于外部执行或包含在脚本中的SQL命令。

还添加了一个新的帮助器方法PGConnection,它使用数据库服务器的默认加密设置为用户执行密码更改操作。这是更新用户密码而不泄露密码的最简单方法。

只支持 ALTER USER ... PASSWORD ...,因为创建用户有许多附加选项,并且可能随时间而更改。

如:

String username = "alice";
String newPassword = "my-new-secret-password";
PGConnection pgConn = conn.unwrap(PGConnection.class);
pgConn.alterUserPassword(username, newPassword.toCharArray(), null);

在创建用户时,推荐的方法是发出CREATE USER…操作,不需要输入密码,然后调用新的PGConnection.alterUserPassword(…)方法。 这些新的帮助程序将在PGJDBC驱动程序的下一个版本中提供。

node.js - pg-password-util

https://www.npmjs.com/package/pg-password-util

在node.js上,您可以使用pg-password-util。这是一个NPM模块(由我编写),加密密码客户端,并有更新现有用户密码的助手。

它被设计为与最流行的PostgreSQL驱动程序一起工作,用于node.js。更新一个用户的密码。

import { alterUserPassword } = require('pg-password-util');

// client is a pg.Client
await alterUserPassword(client, {
username: 'app',
password: 'my-new-secret-password',
});

使用此Helper,明文密码永远不会通过网络发送,也不会出现在任何服务器日志中。

python - psycopg's encrypt_password

https://www.psycopg.org/psycopg3/docs/api/pq.html#psycopg.pq.PGconn.encrypt_password

Python的psycopg驱动程序是libpq (PostgreSQL C库)的包装器。它包含一个python函数封装PQencryptPasswordConn(…)上面提到的C函数:

>>> enc = conn.info.encoding
>>> encrypted = conn.pgconn.encrypt_password(password.encode(enc), rolename.encode(enc))
b'SCRAM-SHA-256$4096:...

返回值是一个字符串,可以包含在ALTER USER ... PASSWORD ...

感谢Robert Ladyman推荐这个Python库。

密码生成

如果不是很明显,上面的abcd密码是一个糟糕的密码。真正的密码,特别是像应用程序数据库用户这样的服务帐户,应该很长,并且是加密随机的。

在大多数*nix环境中,您可以使用以下命令生成一个:

tr -d -c a-zA-Z0-9 </dev/urandom | head -c 43

这将生成一个随机的43个字符的密码。每个字符有62个选项(a-z、a-z或0-9)。每个字符大约有5.954比特的熵(ln(62) / ln2)。43个字符,总共比256位熵多一点。

最终思考

有很多替代密码的方法。(我知道至少有一个人在读到这篇文章时,已经在心里给我写了一封电子邮件,建议每个人都应该使用Kerberos……)但如果你要使用它们,它们就不应该暴露在外面。

使用上面列出的帮助程序,您可以:

1. 生成一个新的长随机密码。
2. 将密码保存到安全的秘密存储中。
3. 使用新的凭据更新数据库用户。

所有这些都不需要在整个过程中以明文形式保存值。

你是否有其他的库应该包含在这篇文章中,或者想进一步扩展它? 让我知道!

欢迎文后留言!

参考资料

[1]

Postgresweekly January 17, 2024: https://postgresweekly.com/issues/538

[2]

背景: https://launchbylunch.com/posts/2024/Jan/16/postgres-password-encryption/#background

[3]

PostgreSQL Password Encryption - MD5: https://launchbylunch.com/posts/2024/Jan/16/postgres-password-encryption/#postgresql-password-encryption-md5

[4]

PostgreSQL Password Encryption - SCRAM-SHA-256: https://launchbylunch.com/posts/2024/Jan/16/postgres-password-encryption/#postgresql-password-encryption-scram-sha-256

[5]

CREATE USER / ALTER USER: https://launchbylunch.com/posts/2024/Jan/16/postgres-password-encryption/#create-user-alter-user

[6]

C - libpq: https://launchbylunch.com/posts/2024/Jan/16/postgres-password-encryption/#c-libpq

[7]

Java - PostgreSQL JDBC Driver (PGJDBC): https://launchbylunch.com/posts/2024/Jan/16/postgres-password-encryption/#java-postgresql-jdbc-driver-pgjdbc

[8]

node.js - pg-password-util: https://launchbylunch.com/posts/2024/Jan/16/postgres-password-encryption/#nodejs-pg-password-util

[9]

python - psycopg's encrypt_password: https://launchbylunch.com/posts/2024/Jan/16/postgres-password-encryption/#python-psycopgs-encrypt_password

[10]

Password Generation: https://launchbylunch.com/posts/2024/Jan/16/postgres-password-encryption/#password-generation

[11]

Final Thoughts: https://launchbylunch.com/posts/2024/Jan/16/postgres-password-encryption/#final-thoughts

[12]

加盐挑战响应认证机制: https://en.wikipedia.org/wiki/Salted_Challenge_Response_Authentication_Mechanism

[13]

key stretching: https://en.wikipedia.org/wiki/Key_stretching

[14]

' PQencryptPasswordConn(…)': https://www.postgresql.org/docs/current/libpq-misc.html#LIBPQ-PQENCRYPTPASSWORDCONN

我是【Sean】,  欢迎大家长按关注并加星公众号:数据库杂记。有好资源相送,同时为你提供及时更新。已关注的朋友,发送0、1到7,都有好资源相送。

往期导读: 
1. PostgreSQL中配置单双向SSL连接详解
2. 提升PSQL使用技巧:PostgreSQL中PSQL使用技巧汇集(1)
3. 提升PSQL使用技巧:PostgreSQL中PSQL使用技巧汇集(2)
4. PostgreSQL SQL的基础使用及技巧
5. PostgreSQL开发技术基础:过程与函数
6. PostgreSQL中vacuum 物理文件truncate发生的条件
7. PostgreSQL中表的年龄与Vacuum的实验探索:Vacuum有大用
8. PostgreSQL利用分区表来弥补AutoVacuum的不足
9. 也聊聊PostgreSQL中的空间膨胀与AutoVacuum
10. 正确理解SAP BTP中hyperscaler PG中的IOPS (AWS篇)

数据库杂记
PostgreSQL,SAP HANA,Sybase ASE/ASA,Oracle,MySQL,SQLite各类数据库, SAP BTP云计算技术, 以及陈式太极拳教学倾情分享。
 最新文章