Ho saputo che i ragazzi del Sun usavano il nome di login come salt per l'hashing della password. È un approccio comune? Quali sono i valori sali più comuni?
Ho saputo che i ragazzi del Sun usavano il nome di login come salt per l'hashing della password. È un approccio comune? Quali sono i valori sali più comuni?
L'uso del nome di accesso come sale è comune ma non consigliato: fa solo una parte del lavoro. Il punto di un sale deve essere il più unico possibile tra tutte le istanze di password hash, in modo da contrastare qualsiasi tentativo di attacco parallelo (attaccando più password con hash contemporaneamente, usando tabelle precompilate come le tabelle arcobaleno ... sono attacchi paralleli). Su sistemi distinti, diversi utenti potrebbero condividere lo stesso nome di accesso (ci sono così tanti Jones e Smith là fuori). Inoltre, un determinato utente può cambiare la sua password mantenendo il suo nome; ma anche una vecchia password è preziosa per un utente malintenzionato (se non altro perché una vecchia password è spesso una password che l'utente riutilizzerà la prossima volta che gli viene richiesto di cambiare la sua password, inoltre molti utenti useranno password identiche su altri sistemi) .
Il modo consigliato per generare un salt è usare un buon generatore di numeri casuali (idealmente crittograficamente strong RNG) e farlo produrre un mucchio di byte casuali. Se il sale è abbastanza lungo (16 byte o più), questo garantisce l'unicità richiesta con una probabilità schiacciante e senza troppi problemi (non è necessario cercare in un database di sali esistenti, ad esempio).
Possiamo solo sperare che questo modo consigliato sia anche, o diventerà presto, il modo "più comune".
Quello che segue è un sistema decente per le password di salatura e hashing. Ci sono un certo numero di punti da tenere a mente, motivo per cui sembra lungo. Questo è un tipico esempio di ciò che dovrebbe fare quando si tratta di salt-hashing; Non parlerò di ciò che fa Sun.
Sali e password possono essere trattati come byte non elaborati ( byte[]
, unsigned char*
, ecc.), nel caso in cui la lingua che si usa si occupa di stringhe di testo in qualche altra forma.
Generiamo un nuovo salt usando un generatore di numeri pseudo-casuali crittograficamente strong per generare il sale. In Ruby, quella libreria è chiamata convenientemente securerandom
. La maggior parte delle lingue ha anche un generatore di numeri casuali, ma non è sufficiente per un sale.
Utilizziamo SHA256 come algoritmo di hash sottostante. Tutti gli algoritmi hash hanno una dimensione di output, che è la dimensione in bit dell'output della funzione hash. Tutti gli algoritmi di hash hanno anche una dimensione interna caratteristica del blocco, che non è la stessa della dimensione di output. Usiamo un sale grande quanto la dimensione del blocco dell'algoritmo hash. Lo facciamo perché questa è la quantità maggiore di entropia che possiamo aggiungere alla password prima di eseguirne l'hashing. Se utilizziamo un sale più grande della dimensione del blocco dell'algoritmo di hash sottostante, HMAC semplicemente salterà per primo il sale per ottenere un sale più piccolo, riducendo la sua entropia, prima di mescolarlo con la password. La dimensione del blocco di SHA256 è 512 bit (= 64 byte), quindi usiamo un sale a 64 byte.
Usiamo HMAC -SHA256 direttamente invece di SHA256, il che fa un po 'più di lavoro per mantenere la password al sicuro. Useremo il sale come parametro chiave per HMAC-SHA256 invece di anteporre la password. HMAC-SHA256 avvolge SHA256 e fa un piccolo lavoro aggiuntivo per unire il sale con la password.
Infine, gli algoritmi hash come SHA-256 sono progettati per essere veloci. Qualunque sia il nostro codice nel complesso, è probabile che spenda l'1% dei suoi tempi per autenticare gli utenti e il 99% di altre cose. Se un utente malintenzionato ottiene una copia del file della password, il suo codice probabilmente spenderà il 100% del proprio tempo per forzare le password. Quindi, rendiamo l'algoritmo generale super-lento: non troppo lento da interferire con il resto del nostro codice, ma abbastanza lento da scoraggiare l'attaccante. Prendiamo un parametro chiamato fattore di lavoro (che potrebbe essere 16) e iterate HMAC-SHA256 2 ^ volte fattore di lavoro (65536 volte nell'esempio). Se il fattore di lavoro fosse 2, sembrerebbe
HMAC-SHA256(salt,
HMAC-SHA256(salt,
HMAC-SHA256(salt,
HMAC-SHA256(salt,
password
)
)
)
)
Una soluzione buona ma semplice in Ruby:
require "securerandom"
require "openssl"
# method for generating a salt and computing a hashed
# version of a password
def salt_hash(password, work_factor)
# get raw bytes from the password string; only needed in Ruby >= 1.9
password = password.force_encoding(Encoding::ASCII_8BIT) if defined?(Encoding)
# use SHA256 as the underlying hash algorithmn
hash = OpenSSL::Digest::SHA256.new
# generate a salt as long as the hash algorithm's block size
# using a cryptographically strong pseudo-random number generator
salt = SecureRandom.random_bytes(hash.new.block_length)
# use HMAC, feeding it two parameters: the salt and the
# underlying hash; since the underlying hash is SHA256,
# this turns it into HMAC-SHA256
hmac = OpenSSL::HMAC.new(salt, hash)
# iterate running HMAC-SHA256 on the password 2^work-factor
# times to make this function slow enough to discourage an
# attacker, but not too slow as to make the service unresponsive
iterations = 2 ** work_factor
iterations.times do
password = hmac.digest(password)
end
# return the salt and the hashed password to whoever called
# this method
{:salt => salt, :hash => password, :work => work_factor}
end
# how to call the method
salt_hash("seekrit", 16)
# and the output would be
=> {:salt => "raw bytes", :hash => "raw bytes", :work => 16}
Leggi altre domande sui tag authentication cryptography passwords hash salt