如何生成 SCRAM-SHA-256 以创建 Postgres 13 用户
How to Generate SCRAM-SHA-256 to Create Postgres 13 User
我想使用 CREATE USER 命令创建一个 Postgres 用户和一个已经散列过的密码摘要。经过大量搜索,我认为只有 MD5 才有可能,直到我找到 this link。我已经验证它是这样工作的:
CREATE USER test_user WITH LOGIN PASSWORD 'SCRAM-SHA-25696:H45+UIZiJUcEXrB9SHlv5Q==$I0mc87UotsrnezRKv9Ijqn/zjWMGPVdy1zHPARAGfVs=:nSjwT9LGDmAsMo+GqbmC2X/9LMgowTQBjUQsl45gZzA=';
然后我可以使用密码登录到该用户,该文章不一定说,但它是“postgres”。现在我知道这是可能的,我如何使用 .NET 5 生成 Postgres 13 将接受的 scram-sha-256 摘要?我看过其他 Postgres 文章使用过时的 MD5 散列,其中用户名在散列之前与密码连接在一起。新的 scram-sha-256 是否也需要发生这种情况?我在任何地方都找不到关于这个主题的太多信息。
我不知道如何使用 .NET 5 生成 scram-sha-256 摘要。
但是,如果您只需要 scram-sha-256 摘要,您可以通过在本地创建虚拟 postgres 用户并使用 createuser
命令回显加密密码来使用变通方法。
例如(通常你 运行 作为 Linux postgres 用户:su postgres
):
$ createuser dummyuser -e --pwprompt
Enter password for new role:
Enter it again:
SELECT pg_catalog.set_config('search_path', '', false);
CREATE ROLE dummyuser PASSWORD 'SCRAM-SHA-25696:VnimR0aOywxZzY82nzy9Fg==$qF9uMCU6YsKoecvRjP8jSmZZxrXgn5VwzhHwfoWo5Xg=:xGYfBUvGsu9mZFiq1nSFaHi7uN8n47IDwHO32IeK9io=' NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT LOGIN;
您现在只需将摘要复制到您的查询中即可。当然,只有在您不需要使用 .NET 动态生成摘要时才有效。
不要忘记删除虚拟用户:
$ dropuser dummyuser
此外,如果您的本地 postgres 数据库仍然是 uses/generates md5,您必须使用以下查询将其更改为 scram,运行 作为 postgres 超级用户:
ALTER SYSTEM SET password_encryption = 'scram-sha-256';
SELECT pg_reload_conf();
但是,如果您想要使用 .NET 动态创建摘要,我建议您查看 createuser
命令的源代码...
一天后更新:
下面是将密码加密成scram-sha-256字符串的createuser
命令的具体源码:
为了让生活更轻松,这里是上述函数调用的函数(可能不是全部)的链接
- https://github.com/postgres/postgres/blob/6beb38cfc9ddd4cd3d2eb5402981ebdd69a618b4/src/common/saslprep.c#L1023-L1245
- https://github.com/postgres/postgres/blob/6beb38cfc9ddd4cd3d2eb5402981ebdd69a618b4/src/common/scram-common.c#L160-L274
您应该能够用 .NET 或任何其他语言重写该代码。希望对您有所帮助!
如果您的目的是在之前生成一个SCRAM-SHA-256密码,那么您有一个可操作的数据库,然后我发现您可以使用此方法生成密码使用 Docker 工具进行散列。
docker run --rm -it --name postgres-dummy -d -e POSTGRES_HOST_AUTH_METHOD=trust postgres:14-alpine
docker exec -it postgres-dummy psql -U postgres
\password
(type in your password twice)
select rolpassword from pg_authid where rolname = 'postgres';
\q
docker stop postgres-dummy
我知道这不是在 .NET 中执行此操作的方法,但希望它对某些人有用。
有人构建了一个 Go 工具来执行此操作:
https://github.com/supercaracal/scram-sha-256
这是一个基于该 Go 项目的 python 3 端口:
from base64 import standard_b64encode
from hashlib import pbkdf2_hmac, sha256
from os import urandom
import hmac
import sys
salt_size = 16
digest_len = 32
iterations = 4096
def b64enc(b: bytes) -> str:
return standard_b64encode(b).decode('utf8')
def pg_scram_sha256(passwd: str) -> str:
salt = urandom(salt_size)
digest_key = pbkdf2_hmac('sha256', passwd.encode('utf8'), salt, iterations,
digest_len)
client_key = hmac.digest(digest_key, 'Client Key'.encode('utf8'), 'sha256')
stored_key = sha256(client_key).digest()
server_key = hmac.digest(digest_key, 'Server Key'.encode('utf8'), 'sha256')
return (
f'SCRAM-SHA-256${iterations}:{b64enc(salt)}'
f'${b64enc(stored_key)}:{b64enc(server_key)}'
)
def print_usage():
print("Usage: provide single password argument to encrypt")
sys.exit(1)
def main():
args = sys.argv[1:]
if args and len(args) > 1:
print_usage()
if args:
passwd = args[0]
else:
passwd = sys.stdin.read().strip()
if not passwd:
print_usage()
print(pg_scram_sha256(passwd))
if __name__ == "__main__":
main()
我遇到了同样的问题,最后我深入研究了 Npgsql 代码并将其与 Shane 的答案结合起来得出了这个问题。它不完全是 battle-hardened,但我确实设法用它创建了一个角色,然后用它登录了。我更喜欢 F#,但将其转换回 C# 并不难。请记住,在 F# 中,函数最后一行的值是该函数的 return 值。此外,在 F# 中,^^^ 是 bitwise-xor 运算符。
let password_hash (password: string) =
let normalized = System.Text.Encoding.UTF8.GetBytes(password.Normalize(System.Text.NormalizationForm.FormKC))
let salt_len = 16
let default_iterations = 4096
let salt = System.Security.Cryptography.RandomNumberGenerator.GetBytes(salt_len)
let mutable salt1 = Array.create (salt.Length + 4) 0uy
let hmac = new System.Security.Cryptography.HMACSHA256(normalized)
System.Buffer.BlockCopy(salt, 0, salt1, 0, salt.Length)
salt1[salt1.Length - 1] <- 1uy
let mutable hi = hmac.ComputeHash(salt1)
let mutable u1 = hi
for _ in 1 .. default_iterations - 1 do
let u2 = hmac.ComputeHash(u1)
for i in 0 .. hi.Length - 1 do
hi[i] <- hi[i] ^^^ u2[i]
u1 <- u2
let client_key = (new System.Security.Cryptography.HMACSHA256(hi)).ComputeHash(System.Text.Encoding.UTF8.GetBytes("Client Key"))
let stored_key = (System.Security.Cryptography.SHA256.Create()).ComputeHash(client_key)
let server_key = (new System.Security.Cryptography.HMACSHA256(hi)).ComputeHash(System.Text.Encoding.UTF8.GetBytes("Server Key"))
let builder = new System.Text.StringBuilder()
builder.Append("'SCRAM-SHA-256$").Append(default_iterations.ToString()).Append(":").Append(System.Convert.ToBase64String(salt)).Append("$")
.Append(System.Convert.ToBase64String(stored_key)).Append(":").Append(System.Convert.ToBase64String(server_key)).Append("'").ToString()
我想使用 CREATE USER 命令创建一个 Postgres 用户和一个已经散列过的密码摘要。经过大量搜索,我认为只有 MD5 才有可能,直到我找到 this link。我已经验证它是这样工作的:
CREATE USER test_user WITH LOGIN PASSWORD 'SCRAM-SHA-25696:H45+UIZiJUcEXrB9SHlv5Q==$I0mc87UotsrnezRKv9Ijqn/zjWMGPVdy1zHPARAGfVs=:nSjwT9LGDmAsMo+GqbmC2X/9LMgowTQBjUQsl45gZzA=';
然后我可以使用密码登录到该用户,该文章不一定说,但它是“postgres”。现在我知道这是可能的,我如何使用 .NET 5 生成 Postgres 13 将接受的 scram-sha-256 摘要?我看过其他 Postgres 文章使用过时的 MD5 散列,其中用户名在散列之前与密码连接在一起。新的 scram-sha-256 是否也需要发生这种情况?我在任何地方都找不到关于这个主题的太多信息。
我不知道如何使用 .NET 5 生成 scram-sha-256 摘要。
但是,如果您只需要 scram-sha-256 摘要,您可以通过在本地创建虚拟 postgres 用户并使用 createuser
命令回显加密密码来使用变通方法。
例如(通常你 运行 作为 Linux postgres 用户:su postgres
):
$ createuser dummyuser -e --pwprompt
Enter password for new role:
Enter it again:
SELECT pg_catalog.set_config('search_path', '', false);
CREATE ROLE dummyuser PASSWORD 'SCRAM-SHA-25696:VnimR0aOywxZzY82nzy9Fg==$qF9uMCU6YsKoecvRjP8jSmZZxrXgn5VwzhHwfoWo5Xg=:xGYfBUvGsu9mZFiq1nSFaHi7uN8n47IDwHO32IeK9io=' NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT LOGIN;
您现在只需将摘要复制到您的查询中即可。当然,只有在您不需要使用 .NET 动态生成摘要时才有效。
不要忘记删除虚拟用户:
$ dropuser dummyuser
此外,如果您的本地 postgres 数据库仍然是 uses/generates md5,您必须使用以下查询将其更改为 scram,运行 作为 postgres 超级用户:
ALTER SYSTEM SET password_encryption = 'scram-sha-256';
SELECT pg_reload_conf();
但是,如果您想要使用 .NET 动态创建摘要,我建议您查看 createuser
命令的源代码...
一天后更新:
下面是将密码加密成scram-sha-256字符串的createuser
命令的具体源码:
为了让生活更轻松,这里是上述函数调用的函数(可能不是全部)的链接
- https://github.com/postgres/postgres/blob/6beb38cfc9ddd4cd3d2eb5402981ebdd69a618b4/src/common/saslprep.c#L1023-L1245
- https://github.com/postgres/postgres/blob/6beb38cfc9ddd4cd3d2eb5402981ebdd69a618b4/src/common/scram-common.c#L160-L274
您应该能够用 .NET 或任何其他语言重写该代码。希望对您有所帮助!
如果您的目的是在之前生成一个SCRAM-SHA-256密码,那么您有一个可操作的数据库,然后我发现您可以使用此方法生成密码使用 Docker 工具进行散列。
docker run --rm -it --name postgres-dummy -d -e POSTGRES_HOST_AUTH_METHOD=trust postgres:14-alpine
docker exec -it postgres-dummy psql -U postgres
\password
(type in your password twice)
select rolpassword from pg_authid where rolname = 'postgres';
\q
docker stop postgres-dummy
我知道这不是在 .NET 中执行此操作的方法,但希望它对某些人有用。
有人构建了一个 Go 工具来执行此操作:
https://github.com/supercaracal/scram-sha-256
这是一个基于该 Go 项目的 python 3 端口:
from base64 import standard_b64encode
from hashlib import pbkdf2_hmac, sha256
from os import urandom
import hmac
import sys
salt_size = 16
digest_len = 32
iterations = 4096
def b64enc(b: bytes) -> str:
return standard_b64encode(b).decode('utf8')
def pg_scram_sha256(passwd: str) -> str:
salt = urandom(salt_size)
digest_key = pbkdf2_hmac('sha256', passwd.encode('utf8'), salt, iterations,
digest_len)
client_key = hmac.digest(digest_key, 'Client Key'.encode('utf8'), 'sha256')
stored_key = sha256(client_key).digest()
server_key = hmac.digest(digest_key, 'Server Key'.encode('utf8'), 'sha256')
return (
f'SCRAM-SHA-256${iterations}:{b64enc(salt)}'
f'${b64enc(stored_key)}:{b64enc(server_key)}'
)
def print_usage():
print("Usage: provide single password argument to encrypt")
sys.exit(1)
def main():
args = sys.argv[1:]
if args and len(args) > 1:
print_usage()
if args:
passwd = args[0]
else:
passwd = sys.stdin.read().strip()
if not passwd:
print_usage()
print(pg_scram_sha256(passwd))
if __name__ == "__main__":
main()
我遇到了同样的问题,最后我深入研究了 Npgsql 代码并将其与 Shane 的答案结合起来得出了这个问题。它不完全是 battle-hardened,但我确实设法用它创建了一个角色,然后用它登录了。我更喜欢 F#,但将其转换回 C# 并不难。请记住,在 F# 中,函数最后一行的值是该函数的 return 值。此外,在 F# 中,^^^ 是 bitwise-xor 运算符。
let password_hash (password: string) =
let normalized = System.Text.Encoding.UTF8.GetBytes(password.Normalize(System.Text.NormalizationForm.FormKC))
let salt_len = 16
let default_iterations = 4096
let salt = System.Security.Cryptography.RandomNumberGenerator.GetBytes(salt_len)
let mutable salt1 = Array.create (salt.Length + 4) 0uy
let hmac = new System.Security.Cryptography.HMACSHA256(normalized)
System.Buffer.BlockCopy(salt, 0, salt1, 0, salt.Length)
salt1[salt1.Length - 1] <- 1uy
let mutable hi = hmac.ComputeHash(salt1)
let mutable u1 = hi
for _ in 1 .. default_iterations - 1 do
let u2 = hmac.ComputeHash(u1)
for i in 0 .. hi.Length - 1 do
hi[i] <- hi[i] ^^^ u2[i]
u1 <- u2
let client_key = (new System.Security.Cryptography.HMACSHA256(hi)).ComputeHash(System.Text.Encoding.UTF8.GetBytes("Client Key"))
let stored_key = (System.Security.Cryptography.SHA256.Create()).ComputeHash(client_key)
let server_key = (new System.Security.Cryptography.HMACSHA256(hi)).ComputeHash(System.Text.Encoding.UTF8.GetBytes("Server Key"))
let builder = new System.Text.StringBuilder()
builder.Append("'SCRAM-SHA-256$").Append(default_iterations.ToString()).Append(":").Append(System.Convert.ToBase64String(salt)).Append("$")
.Append(System.Convert.ToBase64String(stored_key)).Append(":").Append(System.Convert.ToBase64String(server_key)).Append("'").ToString()