Un sitio ben feito non sabe o teu contrasinal. Non é que non queira: é que non pode.
Soa a truco, porque cada vez que o escribes o sistema déixate pasar, e para deixarte pasar ten que comprobar algo. Pero comprobar non é saber. O servidor garda unha pegada calculada a partir do teu contrasinal; cando escribes, volve calcular a pegada e compara. Se coinciden, adiante. En ningún momento fai falla que o contrasinal estea escrito en ningures.
De aí sae o sinal máis claro para distinguir un servizo serio doutro que non o é: se ao esquecelo cho envían por correo, tíñano gardado. E o que está gardado acaba, antes ou despois, en mans doutra persoa.
1979 a idea de non gardalos — e a de facelo amodo
En 1979, Robert Morris e Ken Thompson publicaron en Communications of the ACM «Password Security: A Case History», contando o que fixeran en Unix. É un relato do aprendido, e nel quedan asentadas dúas ideas que hoxe damos por evidentes.
A primeira non a inventaron eles —gardar o hash en lugar do contrasinal xa se facía antes—, pero explicárona mellor ca ninguén: non gardar o contrasinal, gardar o seu hash. Unha función que converte o teu contrasinal nun valor de aspecto arbitrario e que non se pode desandar: do hash non se volve ao contrasinal.
A segunda si é súa: o sal. Un valor aleatorio distinto para cada usuario, que se mestura co contrasinal antes de calcular o hash. Sen sal, dúas persoas co mesmo contrasinal teñen o mesmo hash —o ficheiro roubado convértese nun xogo de buscar repetidos— e, peor aínda, alguén pode precalcular unha táboa xigante unha vez e usala contra todas as bases de datos do mundo. O sal non fai o teu contrasinal máis difícil de adiviñar: fai que adiviñalo non lle sirva a ninguén máis.
Pero nese mesmo artigo hai unha terceira idea, moito menos citada, e é a que importa aquí: fixeron a función deliberadamente lenta. Non por descoido. A mantenta. Cifrar un contrasinal custaba moito máis do que tecnicamente facía falla, porque a quen entra unha vez cada mañá tanto lle ten, e a quen proba millóns de candidatas non.
Aí está todo o asunto nunha frase de hai case cincuenta anos.
Por que a lentitude é a única defensa honesta
Case todas as defensas informáticas son asimétricas: cústanlle pouco a quen se defende e moito a quen ataca. Cifrar é barato; descifrar sen a clave é inviable. O defensor xoga con vantaxe estrutural.
O almacenamento de contrasinais non. Aquí defensor e atacante executan exactamente a mesma función. Ti calculas o hash para comprobar que acertaches; el calcúlao para comprobar se acertou. É a única carreira da seguridade onde os dous corren coas mesmas pernas.
Cando non podes correr máis ca o teu rival, só queda unha xogada: encarecer a pista para os dous. Ti pagas ese custo unha vez por inicio de sesión. El, unha vez por intento. Como necesita ordes de magnitude máis intentos ca ti, a mesma factura afectávos de forma incomparable. Iso é o que fai un hash de contrasinais.
Por iso as funcións rápidas e boísimas para outras cousas —SHA-256, por exemplo— son unha elección pésima aquí. Son rápidas. Rápido é exactamente o que non queremos.
1999 bcrypt, e o custo como peza axustable
O problema dunha función lenta é que o hardware non queda quieto. O que en 1979 era lento, despois é instantáneo. Unha defensa calibrada contra os ordenadores dunha década avellenta soa, sen que ninguén a toque.
En 1999, Niels Provos e David Mazières presentaron bcrypt na USENIX Annual Technical Conference, cun título que xa o di todo: A Future-Adaptable Password Scheme.
A idea: que o custo non estea na función, senón nun parámetro. bcrypt leva un factor de custo que decides ti e que se garda xunto ao hash. Se o hardware se volve moito máis rápido, subes o número e os contrasinais novos volven custar o que deben, sen cambiar de algoritmo.
É un deseño que asume a súa propia obsolescencia e se prepara para ela. Hai poquísimo software que faga iso.
2009 scrypt, e o descubrimento de que o tempo non chega
bcrypt encarece o tempo de cálculo, e funcionou. Ata que o atacante deixou de usar o mesmo tipo de máquina ca o defensor.
Un servidor ten uns poucos núcleos rápidos e de propósito xeral. Unha GPU ten unha barbaridade de núcleos pequenos facendo o mesmo en paralelo, e un ASIC vai máis lonxe: silicio fabricado para executar unha soa operación. Se a túa defensa consiste en «esta operación custa X», alguén pode construír hardware que faga moitas X á vez. O defensor segue co seu servidor.
En 2009, Colin Percival presentou scrypt con outro argumento: Stronger Key Derivation via Sequential Memory-Hard Functions. Se o custo está só no cálculo, paralelízase. Pero a memoria non se regala. Obriga a función a usar moita RAM e a percorrela de forma que non se poida esquivar, e de súpeto o atacante non pode multiplicar núcleos: cada núcleo necesitaría a súa propia memoria. E os núcleos dunha GPU teñen moita potencia e moi pouca RAM para cada un.
Percival non encareceu a operación. Encareceu o hardware necesario para repetila en masa. É un cambio de nivel: atácase o orzamento do atacante, non o seu reloxo.
2015 Argon2, e o final do debate
Que existisen varias opcións razoables non lle axudaba a ninguén a escoller. Así que a comunidade criptográfica fixo o que adoita facer cando quere rematar un asunto: un concurso público. A Password Hashing Competition recibiu candidatos, sometounos a análise aberta durante anos e en 2015 proclamou gañador a Argon2.
Argon2 herda as dúas leccións: custo en tempo e custo en memoria, ambos os dous axustables por separado, máis o número de fíos. Non é maxia. É a síntese ordenada de 1979, 1999 e 2009, revisada por xente cuxo traballo consistía en intentar rompela.
Que significa isto para ti
Case nada disto está nas túas mans, e convén dicilo: o hash escólleo o sitio, non ti. Podes ter o mellor contrasinal do mundo e que cho garden en texto plano nunha folla de cálculo.
Pero o outro lado da ecuación si depende de ti. Todo este edificio —o sal, o custo, a memoria— serve para encarecer cada intento do atacante. O que decide cantos intentos precisa é o teu contrasinal. Se está nun dicionario, ningunha función lenta te salva: caerá entre os primeiros. Se é longo e non se parece a nada, ese prezo por intento multiplícase por un número de intentos que non colle no tempo dispoñible.
Por iso o noso xerador mide bits de entropía e non porcentaxes, e por iso o comprobador busca o teu contrasinal en dicionarios antes que contar símbolos. Eles poñen o prezo por intento; ti pos o número de intentos. Ningunha das dúas metades funciona sen a outra.
E si: segue sendo a mesma pregunta de sempre. Só que agora, do outro lado, alguén intenta respondela moitas veces por segundo, e levamos desde 1979 intentando que cada unha desas veces lle custe cartos.
Fontes: R. Morris e K. Thompson, «Password Security: A Case History», Communications of the ACM, 1979 · N. Provos e D. Mazières, «A Future-Adaptable Password Scheme», USENIX Annual Technical Conference, 1999 (bcrypt) · C. Percival, «Stronger Key Derivation via Sequential Memory-Hard Functions», 2009 (scrypt) · Password Hashing Competition, gañador Argon2, 2015.