2008-12-01 12 views
9

En primer lugar, contexto: estoy tratando de crear una herramienta basada en línea de comandos (Linux) que requiere iniciar sesión. Las cuentas en esta herramienta no tienen nada que ver con las cuentas de nivel de sistema ; nada de esto se ve en/etc/passwd.Módulo de cripta Python: ¿cuál es el uso correcto de sales?

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 de nivel de sistema, usar crypt parecía como una buena práctica de usar, en lugar de almacenar contraseñas en texto sin formato. (Mientras que la cripta es ciertamente mejor que el almacenamiento de contraseñas en texto plano , estoy abierto a otras formas de hacer esto.)

Mi conocimiento de la cripta se basa en esto: https://docs.python.org/2/library/crypt.html

La documentación parece pedir algo eso no es posible: "se recomienda usar la contraseña criptada completa como sal al marcar para obtener 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 un sal? No existe . (Supongo que debe usar la misma sal para crear y verificar una contraseña.)

He intentado utilizar la contraseña de texto plano como una sal. Esto hace que funcione, 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 este problema al no escribir los dos primeros caracteres al archivo:

user_record = '%s:%s:%s' % (user_name, crypted_pw[2:], user_type) 

2) Mediante el uso de la contraseña en texto plano en forma de sal, que parecería ser reducir la cantidad de entropía en el sistema. Posiblemente estoy malentendiendo el propósito de la sal.

La mejor práctica que he podido derivar es utilizar los primeros dos caracteres del nombre de usuario como sal. ¿Esto 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 contraseñas de hash de un diccionario. Podría utilizar una sal estándar para todas las contraseñas (como mis iniciales, "JS"), pero eso parece menos carga de para un atacante que el uso de dos caracteres del nombre de usuario de cada usuario.

Respuesta

4

Para el uso del módulo de la cripta:

al generar la contraseña encriptada, que proporcionan 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 w/conexiones reales del sistema, no hay nada que no le permite utilizar un método más fuerte que la cripta. 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 aún 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.

+2

prefiera PBKDF2 para guardar contraseñas: aplique la sal con HMAC e itere – orip

3

Está mal entendiendo la documentación; indica que, dado que la longitud de la sal puede variar según la implementación crypt() subyacente, debe proporcionar toda la contraseña cifrada 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.

Su idea de tener la sal inicial basada en el nombre de usuario parece estar bien.

3

He aquí algunos consejos generales sobre las contraseñas de salazón:

  1. En general, las sales se utilizan para hacer ranbow tables demasiado costoso 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.
  2. Use HMAC - es un buen estándar, y es más seguro que concatenar la contraseña y la sal.
  3. Usar SHA1: MD5 está roto. Sin ánimo de ofender si supieras esto, solo siendo minucioso. ;)

I no sería tienen la sal en 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).

7

Python's crypt() es un contenedor para la función crypt() del sistema. Desde la página del Linux cripta():

 
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 "de dos caracteres cadena". Ahora, si nos fijamos en las criptas() 's comportamiento en Python:

>>> crypt.crypt("Hello", "World") 
'Wo5pEi/H5/mxU' 
>>> crypt.crypt("Hello", "ABCDE") 
'AB/uOsC7P93EI' 

se descubre que los dos primeros caracteres del resultado siempre coinciden con los dos primeros caracteres de la sal original, que de hecho forman los dos cierto -character-sal en sí. 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 como dos caracteres se relacionan con " formas diferentes".

1

La contraseña, o cualquier cosa derivada de la contraseña, nunca se debe utilizar como salt.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.

2

Para obtener una mayor resistencia, puede obtener el módulo crypt para usar md5 utilizando una sal en el formato.

$1$ABCDEFGH$ 

donde ABCDEFGH es su 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 esto es una extensión de GNU a la cripta, consulte "hombre cripta" 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.

+1

Tenga en cuenta que si sus sistemas lo permiten, puede incluso hacer: 'crypt.crypt (" some_password "," $ 5 $ some_salt ")' o 'crypt.crypt ("some_password", "$ 6 $ some_salt") 'para usar sha-256 o sha-512 si no confía en MD5. También tenga en cuenta que crypt utiliza varias rondas de DES/MD5/SHA * para que sea más seguro y solo utiliza una sola ronda. Entonces, romper MD5 no significa automáticamente que la cripta con $ 1 $ es. – koffie

1

Utilice PBKDF2, consulte this comment en un hilo diferente (incluye la implementación de Python).

-1

Eche un vistazo al artículo TrueCrypt explained de 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 el módulo Python crypt(), no se trata de TrueCrypt en Python

defecto crypt.crypt() en Python 2 no es muy seguro y the article explica cómo podrían funcionar las alternativas más seguras.

+1

Habla del módulo Python crypt(), no de TrueCrypt en Python. – Kitchi

Cuestiones relacionadas