Memorizzare i valori hash SHA1 in MySQL


160

Ho una semplice domanda che si è presentata quando volevo archiviare il risultato di un hash SHA1 in un database MySQL:

Quanto deve essere lungo il campo VARCHAR in cui memorizzo il risultato dell'hash?


9
Se hai appena cercato su Google sha1 fai clic su Mi sento fortunato e dovresti essere su Wikipedia dove puoi trovarlo sempre a 160 bit.
Tim Matthews,

Risposte:


315

Vorrei utilizzare VARCHARper dati a lunghezza variabile, ma non con dati a lunghezza fissa. Poiché un valore SHA-1 è sempre lungo 160 bit, si VARCHARperderebbe un byte aggiuntivo per la lunghezza del campo a lunghezza fissa .

E inoltre non memorizzerei il valore SHA1restituito. Perché usa solo 4 bit per carattere e quindi avrebbe bisogno di 160/4 = 40 caratteri. Ma se usi 8 bit per carattere, avrai bisogno solo di un campo lungo 160/8 = 20 caratteri.

Quindi ti consiglio di usare BINARY(20)e la UNHEXfunzione per convertire il SHA1valore in binario.

Ho confrontato i requisiti di archiviazione per BINARY(20)e CHAR(40).

CREATE TABLE `binary` (
    `id` int unsigned auto_increment primary key,
    `password` binary(20) not null
);
CREATE TABLE `char` (
    `id` int unsigned auto_increment primary key,
    `password` char(40) not null
);

Con milioni di record binary(20)richiede 44,56 milioni, mentre char(40)richiede 64,57 milioni. InnoDBmotore.


2
In PostgreSQL, ciò si tradurrebbe in un campo bytea, giusto?
mvexel,

La soluzione è ottima, ma c'è un altro punto da usare char (40) con sha1 hexed - questo è molto più ampiamente usato e ci saranno meno problemi di conversione in un codice dell'applicazione.
Arthur Kushman,

2
Nota per gli utenti di phpmyadmin. Quando si memorizza l'hash come binario, phpmyadmin lo visualizzerà come una stringa esadecimale, ma pma non sarà in grado di usarlo nella "scheda di ricerca" fornita. Funzionerà solo se aggiungi UNHEX()manualmente a sql.
Timo Huovinen,

2
@Gumbo È possibile memorizzare un numero variabile di byte in un bytea. Ti riferisci ai requisiti di archiviazione del tipo bytea. Che è "1 o 4 byte più la stringa binaria effettiva". Ciò a cui fa riferimento "1 o 4" potrebbe essere la lunghezza dei dati memorizzati, poiché non è possibile utilizzare un byte zero per terminare la stringa come si fa con varchar. Ciò implica, ma non è indicato nel manuale, che è possibile memorizzare fino a 2 ^ (8 * 4) o 4+ gigabyte in un byte. postgresql.org/docs/9.0/static/datatype-binary.html La memorizzazione dell'hash in un database Postgres sarebbe probabilmente la più piccola di una colonna bit o bytea.
Viktor,

2
dev.mysql.com/doc/refman/5.5/it/… fornisce informazioni su prestazioni e archiviazione durante la memorizzazione dei risultati delle funzioni di
crittografia


11

Riferimento tratto da questo blog:

Di seguito è riportato un elenco di algoritmi di hashing insieme alle dimensioni dei bit richieste:

  • MD5 = valore hash a 128 bit.
  • SHA1 = valore hash a 160 bit.
  • SHA224 = valore hash di 224 bit.
  • SHA256 = valore hash a 256 bit.
  • SHA384 = valore hash a 384 bit.
  • SHA512 = valore hash a 512 bit.

Creata una tabella di esempio con richiesta CHAR (n):

CREATE TABLE tbl_PasswordDataType
(
    ID INTEGER
    ,MD5_128_bit CHAR(32)
    ,SHA_160_bit CHAR(40)
    ,SHA_224_bit CHAR(56)
    ,SHA_256_bit CHAR(64)
    ,SHA_384_bit CHAR(96)
    ,SHA_512_bit CHAR(128)
); 
INSERT INTO tbl_PasswordDataType
VALUES 
(
    1
    ,MD5('SamplePass_WithAddedSalt')
    ,SHA1('SamplePass_WithAddedSalt')
    ,SHA2('SamplePass_WithAddedSalt',224)
    ,SHA2('SamplePass_WithAddedSalt',256)
    ,SHA2('SamplePass_WithAddedSalt',384)
    ,SHA2('SamplePass_WithAddedSalt',512)
);

10
Per favore , per favore , per favore non archiviare password come questa.
Berry M.,

Ehi bacca, puoi spiegare il tuo PERCHÉ? in dettaglio
Anvesh,

4
La memorizzazione di semplici hash delle password rende molto più semplice "estrarre" le password se il database è compromesso che se si utilizza un hash di password salato (si spera allungato). Lettura consigliata: paragonie.com/blog/2016/02/how-safely-store-password-in-2016
matt

2
@BerryM. leggendo questo un anno dopo, e per un secondo non ho pensato che qualcuno stesse parlando di password o che se le persone usano ancora un semplice hash per archiviare i dati di autenticazione. Ma lo fanno: D
Rohit Hazra,

6

La dimensione di uscita di sha1 è di 160 bit. Che è 160/8 == 20 caratteri (se si utilizzano caratteri a 8 bit) o ​​160/16 = 10 (se si utilizzano caratteri a 16 bit).


Supponendo caratteri binari a 8 bit. 40 caratteri se memorizzati come esadecimali.
Tyzoid,

3

Quindi la lunghezza è compresa tra 10 caratteri a 16 bit e 40 cifre esadecimali.

In ogni caso, decidere il formato che si intende memorizzare e rendere il campo di dimensioni fisse in base a tale formato. In questo modo non avrai alcuno spazio sprecato.


2

Potresti comunque voler utilizzare VARCHAR nei casi in cui non memorizzi sempre un hash per l'utente (ovvero autenticazione di account / URL di accesso dimenticato). Una volta che un utente ha autenticato / modificato le informazioni di accesso, non dovrebbe essere in grado di utilizzare l'hash e non dovrebbe avere motivo di farlo. È possibile creare una tabella separata per memorizzare hash temporanei -> associazioni di utenti che potrebbero essere eliminate, ma non credo che la maggior parte delle persone si preoccupi di farlo.


2

Se hai bisogno di un indice sulla colonna sha1, ti consiglio CHAR (40) per motivi di prestazioni. Nel mio caso la colonna sha1 è un token di conferma e-mail, quindi nella pagina di destinazione la query entra solo con il token. In questo caso CHAR (40) con INDEX, secondo me, è la scelta migliore :)

Se vuoi adottare questo metodo, ricorda di lasciare $ raw_output = false.


1
Perché non indicizzeresti BINARY (20)? Non sarebbe altrettanto veloce e grande la metà?
Nickdnk,

Bene ~ 5 anni fa, ma penso che mi riferissi al fatto che hai ancora bisogno di unhex che aggiunge un po 'di carico (+ rende l'applicazione più difficile da mantenere e meno portatile?). Dipende anche dal tuo hardware, se hai meno spazio di archiviazione ed è lento, probabilmente è meglio attenersi al binario (20), altrimenti direi char (40). Difficile dirlo senza eseguire alcuni test con la lingua e l'hardware che useresti e vedere ciò che fa per te.
Francesco Casula,

1
Suppongo che se stai facendo qualcosa di diverso da selezionare da dove unhex (hash) = hash per recuperare una singola riga, allora forse hai ragione. Ma mantenere l'indice bufferizzato richiederà il doppio della memoria in questo modo.
Nickdnk,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.