password - python encrypt string
Módulo de cripta Python: ¿cuál es el uso correcto de sales? (8)
Aquí hay algunos consejos generales sobre las contraseñas de salazón:
- En general, las sales se utilizan para hacer tablas de randas demasiado costosas para calcular. Por lo tanto, debe agregar un poco de sal aleatoria a todos sus valores hash de contraseña, y simplemente almacenarlo en texto plano junto al valor de contraseña hash.
- Use HMAC : es un buen estándar y es más seguro que concatenar la contraseña y la sal.
- Use SHA1: MD5 está roto. Sin ánimo de ofender si supieras esto, solo siendo minucioso. ;)
No quisiera que la sal sea una función de la contraseña. Un atacante tendría que generar una tabla de arco iris para tener una base de datos de contraseñas de búsqueda instantánea, pero solo tendrían que hacer eso una vez. Si eliges un entero aleatorio de 32 bits, tendrían que generar 2 ^ 32 tablas, lo que (a diferencia de una sal determinista) cuesta mucho, demasiada memoria (y tiempo).
Primero, contexto: estoy tratando de crear una herramienta basada en línea de comandos (Linux) que requiera iniciar sesión. Las cuentas en esta herramienta no tienen nada que ver con las cuentas a nivel del sistema; nada de esto se ve en / etc / passwd.
Estoy planeando almacenar cuentas de usuario en un archivo de texto usando el mismo formato (más o menos) que / etc / passwd.
A pesar de no utilizar los archivos de contraseñas a nivel del sistema, el uso de crypt parecía ser una buena práctica para usar, en lugar de almacenar contraseñas en texto sin formato. (Aunque crypt es ciertamente mejor que almacenar contraseñas en texto claro, estoy abierto a otras formas de hacerlo).
El conocimiento de mi cripta se basa en esto: https://docs.python.org/2/library/crypt.html
La documentación parece pedir algo que no es posible: "se recomienda utilizar la contraseña criptada completa como sal cuando se busca una contraseña".
¿Huh? Si estoy creando la contraseña cifrada (como en, al crear un registro de usuario) ¿cómo puedo usar la contraseña cifrada como una sal? No existe todavía (Supongo que debe usar la misma sal para crear y verificar una contraseña).
He intentado usar la contraseña de texto plano como una sal. Esto funciona, pero tiene dos problemas; uno fácil de superar, y uno serio:
1) Las primeras dos letras de la contraseña de texto plano se incluyen en la contraseña cifrada. Puede solucionar esto al no escribir los dos primeros caracteres en el archivo:
user_record = ''%s:%s:%s'' % (user_name, crypted_pw[2:], user_type)
2) Al utilizar la contraseña de texto simple como sal, parece que está reduciendo la cantidad de entropía en el sistema. Posiblemente no estoy entendiendo el propósito de la sal.
La mejor práctica que he podido derivar es usar los primeros dos caracteres del nombre de usuario como sal. ¿Sería apropiado, o hay algo que he echado de menos que hace que sea un mal movimiento?
Mi comprensión de una sal es que previene hash de contraseñas de contraseña de un diccionario. Podría usar una sal estándar para todas las contraseñas (como mis iniciales, "JS"), pero eso parece ser una carga menor para un atacante que el uso de dos caracteres del nombre de usuario de cada usuario.
Eche un vistazo al artículo TrueCrypt explicado por Björn Edström. Contiene una explicación fácil de entender de cómo funciona truecrypt y una implementación simple de Python de algunas de las funciones de Truecrypt, incluida la administración de contraseñas .
Está hablando del módulo Python crypt (), no de TrueCrypt en Python
El crypt.crypt()
predeterminado crypt.crypt()
en Python 2 no es muy seguro y el artículo explica cómo podrían funcionar alternativas más seguras.
Estás malinterpretando la documentación; dice que dado que la longitud de la sal puede variar dependiendo de la implementación de crypt () subyacente, debe proporcionar la contraseña criptada completa como el valor de sal al verificar las contraseñas . Es decir, en lugar de tirar los dos primeros chars para que sean la sal, simplemente mezcle todo.
Tu idea de tener la sal inicial basada en el nombre de usuario parece estar bien.
La contraseña, o cualquier cosa derivada de la contraseña, nunca debe usarse como sal. La sal para una contraseña particular debe ser impredecible.
Un nombre de usuario o parte del nombre de usuario es tolerable, pero aún mejor serían los bytes aleatorios de un RNG criptográfico.
Para el uso del módulo crypt:
Al GENERAR la contraseña cifrada, proporciona la sal. También podría ser aleatorio aumentar la resistencia a la fuerza bruta, siempre que cumpla con las condiciones enumeradas. Cuando se CHECCA una contraseña, debe proporcionar el valor de getpwname, en caso de que esté en un sistema que admita tamaños de sal más grandes y no lo generó usted mismo.
Comentarios generales:
Si esto no tiene nada que ver con los inicios de sesión actuales del sistema, no hay nada que le impida usar un método más fuerte que crypt. Puede generar aleatoriamente N caracteres de sal por usuario, que se combinarán con la contraseña del usuario en un hash SHA-1.
string_to_hash = user.stored_salt + entered_password
successful_login = (sha1(string_to_hash) == user.stored_password_hash)
ACTUALIZACIÓN: Si bien esto es mucho más seguro contra las tablas del arco iris, el método anterior todavía tiene debilidades criptográficas. La correcta aplicación de un algoritmo HMAC puede aumentar aún más su seguridad, pero está más allá de mi dominio de la experiencia.
Para obtener un poco de fuerza adicional, puede hacer que el módulo crypt use md5 utilizando una sal en el formato.
$1$ABCDEFGH$
donde ABCDEFGH es tu cadena de sal.
>>> p = crypt.crypt(''password'', ''$1$s8Ty3/f$'')
>>> p
Out: ''$1$s8Ty3/f$0H/M0JswK9pl3X/e.n55G1''
>>> p == crypt.crypt(''password'', p)
Out: True
(tenga en cuenta que esta es una extensión gnu para crypt, consulte "man crypt" en un sistema Linux). MD5 (y ahora incluso SHA1) puede estar "roto", pero todavía son relativamente buenos para los hash de contraseñas, y md5 sigue siendo el estándar para las contraseñas locales de Linux.
Python''s crypt () es un contenedor para la función crypt () del sistema. Desde la página man de crypt () de Linux:
char *crypt(const char *key, const char *salt); key is a user’s typed password. salt is a two-character string chosen from the set [a–zA–Z0–9./]. This string is used to perturb the algorithm in one of 4096 different ways.
El énfasis está en "cadena de dos caracteres ". Ahora, si observas el comportamiento de crypt () en Python:
>>> crypt.crypt("Hello", "World")
''Wo5pEi/H5/mxU''
>>> crypt.crypt("Hello", "ABCDE")
''AB/uOsC7P93EI''
descubres que los primeros dos caracteres del resultado siempre coinciden con los dos primeros caracteres de la sal original, que de hecho forman la verdadera sal de dos caracteres. Es decir, el resultado de crypt () tiene la forma 2char-salt + encrypted-pass. Por lo tanto, no hay diferencia en el resultado si en lugar de pasar la sal de dos caracteres o la sal original de muchos caracteres pasa la contraseña encriptada completa.
Nota: el conjunto [a-zA-Z0-9./] contiene 64 caracteres, y 64 * 64 = 4096. Así es cómo dos personajes se relacionan con " 4096 maneras diferentes".
Use PBKDF2, vea este comentario en un hilo diferente (incluye la implementación de Python).