Quiero crear un usuario de Postgres con el comando CREAR USUARIO y un resumen ya cifrado para la contraseña. Después de mucho buscar, pensé que solo era posible con MD5 hasta que encontré este enlace. He comprobado que funciona así:
CREATE USER test_user WITH LOGIN PASSWORD 'SCRAM-SHA-256$4096:H45+UIZiJUcEXrB9SHlv5Q==$I0mc87UotsrnezRKv9Ijqn/zjWMGPVdy1zHPARAGfVs=:nSjwT9LGDmAsMo+GqbmC2X/9LMgowTQBjUQsl45gZzA=';Luego puedo iniciar sesión en ese usuario con la contraseña, que el artículo no necesariamente dice, pero es "postgres". Ahora que sé que es posible, ¿cómo puedo usar .NET 5 para generar un resumen scram-sha-256 que aceptará Postgres 13? He visto otros artículos de Postgres que usan el hash MD5 desactualizado donde el nombre de usuario se concatena con la contraseña antes del hash. ¿Eso también debe suceder con el nuevo scram-sha-256? No pude encontrar mucha información sobre este tema en ningún lado.
No sé cómo generar un resumen scram-sha-256 con .NET 5. Sin embargo, si el resumen scram-sha-256 es todo lo que necesita, puede usar una solución alternativa creando un usuario postgres ficticio localmente y haciendo eco del cifrado contraseña con el comando createuser .
Por ejemplo (por lo general, ejecuta esto como usuario de 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-256$4096:VnimR0aOywxZzY82nzy9Fg==$qF9uMCU6YsKoecvRjP8jSmZZxrXgn5VwzhHwfoWo5Xg=:xGYfBUvGsu9mZFiq1nSFaHi7uN8n47IDwHO32IeK9io=' NOSUPERUSER NOCREATEDB NOCREATEROLE INHERIT LOGIN;Ahora puede simplemente copiar el resumen en su consulta. Por supuesto, eso solo funciona si no necesita generar el resumen dinámicamente con .NET.
No olvides eliminar al usuario ficticio:
$ dropuser dummyuserAdemás, en caso de que su base de datos local de postgres todavía use/genera md5, debe cambiar eso para eliminarlo usando la siguiente consulta, ejecutada como superusuario de postgres:
ALTER SYSTEM SET password_encryption = 'scram-sha-256'; SELECT pg_reload_conf(); Sin embargo, si desea crear el resumen dinámicamente con .NET, le recomiendo que eche un vistazo al código fuente del comando createuser ...
Actualización un día después:
Aquí está el código fuente específico del comando createuser que cifra la contraseña en una cadena scram-sha-256:
Para hacer la vida más fácil, aquí hay enlaces a las funciones (probablemente no todas) que llama la función anterior
Debería poder reescribir ese código en .NET o en cualquier otro idioma. ¡Espero eso ayude!
Si su intención es generar una contraseña SCRAM-SHA-256 antes de tener una base de datos operativa, descubrí que puede usar este método para generar un hash de contraseña usando las herramientas de 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-dummySé que no es una forma de hacerlo en .NET, pero espero que sea útil para alguien.
Alguien creó una herramienta Go para hacer esto:
https://github.com/supercaracal/scram-sha-256
Aquí hay un puerto python 3 basado en ese proyecto Go:
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()