python passlib: ¿cuál es el mejor valor para "rondas"
encryption pbkdf2 (1)
de la documentación de passlib
Para la mayoría de los servicios públicos, generalmente puede iniciar sesión para tomar más de 250ms - 400ms antes de que los usuarios comiencen a molestarse.
Entonces, ¿cuál es el mejor valor para las rounds
en un inicio de sesión / registro si consideramos que hay una llamada para la base de datos para el intento de inicio de sesión y usa MongoDB con una llamada no bloqueante ? (utilizando Mongotor , y utilizando el correo electrónico como _id
, por lo que está indexado por defecto, la consulta es rápida: 0.00299978256226 y, por supuesto, probado con una base de datos que tiene 3 registros ...)
import passlib.hash
import time
hashh = passlib.hash.pbkdf2_sha512
beg1 = time.time()
password = hashh.encrypt("test", salt_size = 32, rounds = 12000)
print time.time()- beg1 # returns 0.142999887466
beg2 = time.time()
hashh.verify("test", password) # returns 0.143000125885
print time.time()- beg2
ahora si uso medio valor:
password = hashh.encrypt("test", salt_size = 32, rounds = 4000) # returns 0.0720000267029
hashh.verify("test", password) # returns 0.0709998607635
estoy usando Windows 7 64 bits en Dell XPS 15 i7 2.0 Ghz
NB: instaló bcrypt , y por supuesto, es un verdadero dolor usarlo directamente como sus valores predeterminados ( rounds = 12
):
hashh = passlib.hash.bcrypt
beg1 = time.time()
password = hashh.encrypt("test", rounds = 12) # returns 0.406000137329
print time.time()- beg1
beg2 = time.time()
hashh.verify("test", password) # returns 0.40499997139
print time.time()- beg2
medio valor:
password = hashh.encrypt("test", rounds = 12) # 0.00699996948242 wonderful?
hashh.verify("test", password) # 0.00600004196167
¿Me puede sugerir un buen valor de rondas al usar pbkdf2_sha512
que será bueno para la producción?
(desarrollador de passlib aquí)
La cantidad de tiempo que toma pbkdf2_sha512 es linealmente proporcional a su parámetro de rondas ( elapsed_time = rounds * native_speed
). Usando los datos para su sistema, native_speed = 12000 / .143 = 83916 iterations/second
, lo que significa que necesitará alrededor de 83916 * .350 = 29575 rounds
para obtener ~ 350ms de retraso.
Las cosas son un poco complicadas para bcrypt, porque la cantidad de tiempo que toma es logarítmicamente proporcional a su parámetro de rondas ( elapsed_time = (2 ** rounds) * native_speed
). Usando los datos para su sistema, native_speed = (2 ** 12) / .405 = 10113 iterations/second
, lo que significa que necesitará alrededor de log(10113 * .350, 2) = 11.79 rounds
para obtener ~ 350 ms de retraso. Pero dado que BCrypt solo acepta los parámetros de las rondas enteras, entonces tendrá que elegir rounds=11
(~ 200ms) o rounds=12
(~ 400ms).
Todo esto es algo que espero solucionar en una versión futura de passlib. Como un trabajo en progreso, el repositorio mercurial de passlib actualmente contiene un pequeño script simple, choose_rounds.py , que se encarga de elegir el valor de rondas correcto para un tiempo objetivo dado. Puede descargarlo y ejecutarlo directamente de la siguiente manera (puede tardar unos 20 segundos en ejecutarse):
$ python choose_rounds.py -h
usage: python choose_rounds.py <hash_name> [<target_in_milliseconds>]
$ python choose_rounds.py pbkdf2_sha512 350
hash............: pbkdf2_sha512
speed...........: 83916 iterations/second
target time.....: 350 ms
target rounds...: 29575
$ python choose_rounds.py bcrypt 350
hash............: bcrypt
speed...........: 10113 iterations/second
target time.....: 350 ms
target rounds...: 11 (200ms -- 150ms faster than requested)
target rounds...: 12 (400ms -- 50ms slower than requested)
(editar: respuesta agregada con respecto a rondas mínimas seguras ...)
Descargo de responsabilidad: Determinar un mínimo seguro es una pregunta sorprendentemente difícil: hay una serie de parámetros difíciles de cuantificar, muy pocos datos del mundo real y alguna teoría rigurosamente inútil. Al carecer de una buena autoridad, he estado investigando el tema yo mismo; y para los cálculos fuera del manguito, he reducido los datos sin procesar a una fórmula corta (a continuación), que generalmente es lo que uso. Solo tenga en cuenta que detrás de él hay un par de páginas de suposiciones y estimaciones aproximadas, por lo que es más una estimación de Fermi que una respuesta exacta: |
Mi regla general (mediados de 2012) para atacar a PBKDF2-HMAC-SHA512 usando GPU es:
days * dollars = 2**(n-31) * rounds
-
days
es la cantidad de días antes de que el atacante tenga una probabilidad del 50/50 de adivinar la contraseña. -
dollars
es el presupuesto de hardware de los atacantes (en $ USD). -
n
es la cantidad promedio de entropía en las contraseñas de usuario (en bits).
Para responder a la pregunta del script-kiddie: si una contraseña promedio tiene 32 bits de entropía y el atacante tiene un sistema de $ 2000 con una buena GPU, entonces en 30000 rondas necesitarán 30 días ( 2**(32-31)*30000/2000
) para tener una probabilidad de 50/50 de descifrar un hash dado. Recomiendo jugar con los valores hasta que llegue a una compensación de rondas / días con la que se sienta cómodo.
Algunas cosas para tener en mente:
La tasa de éxito de un ataque de diccionario no es lineal, es más una situación de "cola larga", así que piense en la marca 50/50 como más de una vida media.
Ese
31
es el factor clave, ya que codifica una estimación del costo de atacar un algoritmo específico utilizando un nivel tecnológico específico. El valor real,2**-31
, mide los "días-dólar por ronda" que le costará a un atacante. A modo de comparación, atacar PBKDF2-HMAC-SHA512 usando un ASIC tiene un factor más cercano a46
- números más grandes significan más explosión para el dinero del atacante, y menos seguridad por ronda para ti, aunque los script kiddies generalmente no tendrán ese tipo de presupuesto :)