Przechowywanie wartości skrótu SHA1 w MySQL

160

Mam proste pytanie, które pojawiło się, gdy chciałem zapisać wynik skrótu SHA1 w bazie danych MySQL:

Jak długo powinno być pole VARCHAR, w którym przechowuję wynik skrótu?

niklasfi
źródło
9
Jeśli właśnie wygooglowałeś sha1, kliknij, czuję się szczęśliwy i powinieneś być na Wikipedii, gdzie możesz znaleźć zawsze 160 bitów.
Tim Matthews,

Odpowiedzi:

315

Używałbym VARCHARdo danych o zmiennej długości, ale nie do danych o stałej długości. Ponieważ wartość SHA-1 ma zawsze długość 160 bitów, po VARCHARprostu zmarnuje dodatkowy bajt na długość pola o stałej długości .

Nie chciałbym też przechowywać wartości, którą SHA1zwraca. Ponieważ wykorzystuje tylko 4 bity na znak, a zatem wymagałoby 160/4 = 40 znaków. Ale jeśli używasz 8 bitów na znak, potrzebujesz tylko pola o długości 160/8 = 20 znaków.

Dlatego polecam użycie BINARY(20)i UNHEXfunkcję do konwersji SHA1wartości na binarną.

Porównałem wymagania dotyczące przechowywania dla BINARY(20)i 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
);

Z milionem rekordów binary(20)zajmuje 44,56 mln, podczas gdy char(40)zajmuje 64,57 mln. InnoDBsilnik.

Gumbo
źródło
2
W PostgreSQL oznaczałoby to użycie pola bajtowego, prawda?
mvexel
Rozwiązanie jest świetne, ale jest jeszcze jeden punkt, aby użyć znaku char (40) z szesnastkowym sha1 - jest to znacznie szerzej stosowane i będzie mniej problemów z konwersją w kodzie aplikacji.
Arthur Kushman
2
Uwaga dla użytkowników phpmyadmin. Przechowując hash jako plik binarny, phpmyadmin wyświetli go jako ciąg szesnastkowy, ale pma nie będzie mógł go użyć w podanej "zakładce wyszukiwania". Będzie działać tylko wtedy, gdy dodasz UNHEX()ręcznie plik sql.
Timo Huovinen
2
@Gumbo Możesz przechowywać zmienną liczbę bajtów w bajcie. Masz na myśli wymagania dotyczące przechowywania typu bajt. Czyli „1 lub 4 bajty plus rzeczywisty ciąg binarny”. To, do czego odnosi się „1 lub 4”, może być długością przechowywanych danych, ponieważ nie można użyć bajtu zerowego do zakończenia łańcucha, tak jak robi się to z varchar. Oznacza to, ale nie jest to określone w instrukcji, że można przechowywać do 2 ^ (8 * 4) lub 4+ gigabajtów w bajcie. postgresql.org/docs/9.0/static/datatype-binary.html Przechowywanie hasha w bazie danych postgres byłoby prawdopodobnie najmniejsze jako kolumna bitowa lub bajtowa.
Viktor
2
dev.mysql.com/doc/refman/5.5/en/… zawiera informacje o wydajności i przechowywaniu wyników funkcji kryptograficznych
Clocker
45

Skrót SHA1 ma 40 znaków!

schmilblick
źródło
11

Odniesienie zaczerpnięte z tego bloga:

Poniżej znajduje się lista algorytmów haszujących wraz z wymaganymi rozmiarami bitów:

  • MD5 = 128-bitowa wartość skrótu.
  • SHA1 = 160-bitowa wartość skrótu.
  • SHA224 = 224-bitowa wartość skrótu.
  • SHA256 = 256-bitowa wartość skrótu.
  • SHA384 = 384-bitowa wartość skrótu.
  • SHA512 = 512-bitowa wartość skrótu.

Utworzono jedną przykładową tabelę z wymaganym 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)
);
Anvesh
źródło
10
Proszę, proszę , proszę nie faktycznie przechowywania haseł, takich jak ten.
Berry M.
Hej Berry, czy możesz wyjaśnić dlaczego? szczegółowo
Anvesh
4
Przechowywanie prostych skrótów haseł znacznie ułatwia „wyodrębnianie” haseł, jeśli baza danych jest zagrożona, niż w przypadku korzystania z zasolonego (miejmy nadzieję rozciągniętego) skrótu hasła. Sugerowana lektura: paragonie.com/blog/2016/02/how-safely-store-password-in-2016
mat.
2
@BerryM. czytając to rok później i przez chwilę nie pomyślałem, że ktoś mówi o hasłach lub że ludzie nadal używają prostego skrótu do przechowywania danych uwierzytelniania. Ale robią: D
Rohit Hazra
6

Rozmiar wyjściowy sha1 to 160 bitów. To jest 160/8 == 20 znaków (jeśli używasz 8-bitowych znaków) lub 160/16 = 10 (jeśli używasz 16-bitowych znaków).

inazaruk
źródło
Zakładając 8-bitowe znaki binarne. 40 znaków, jeśli są przechowywane jako szesnastkowe.
Tyzoid
3

Tak więc długość wynosi od 10 16-bitowych znaków do 40 cyfr szesnastkowych.

W każdym razie zdecyduj, jaki format chcesz przechowywać, i ustaw pole o stałym rozmiarze na podstawie tego formatu. W ten sposób nie będziesz miał zmarnowanej przestrzeni.

Douglas Leeder
źródło
2

Możesz nadal używać VARCHAR w przypadkach, gdy nie zawsze przechowujesz hash dla użytkownika (np. Uwierzytelnianie kont / zapomnienie adresu URL logowania). Gdy użytkownik uwierzytelnił / zmienił swoje dane logowania, nie powinien być w stanie użyć skrótu i ​​nie powinien mieć powodu do tego. Możesz utworzyć oddzielną tabelę do przechowywania tymczasowego skrótu -> skojarzenia użytkowników, które można usunąć, ale nie sądzę, aby większość ludzi przejmowała się tym.

Keith Harty
źródło
2

Jeśli potrzebujesz indeksu w kolumnie sha1, sugeruję CHAR (40) ze względu na wydajność. W moim przypadku kolumna sha1 jest tokenem potwierdzającym e-mail, więc na landing page zapytanie wchodzi tylko z tokenem. W tym przypadku moim zdaniem najlepszym wyborem jest CHAR (40) z INDEXEM :)

Jeśli chcesz zastosować tę metodę, pamiętaj o pozostawieniu $ raw_output = false.

Francesco Casula
źródło
1
Dlaczego nie miałbyś indeksować BINARY (20)? Czy nie byłoby to równie szybkie i o połowę mniejsze?
nickdnk
Cóż, to ~ 5 lat temu, ale myślę, że miałem na myśli fakt, że nadal musisz unhex, co dodaje trochę obciążenia (+ sprawia, że ​​aplikacja jest trudniejsza w utrzymaniu i mniej przenośna?). To trochę zależy również od twojego sprzętu, jeśli masz mniej miejsca i jest wolne, prawdopodobnie najlepiej jest trzymać się binarnego (20), w przeciwnym razie powiedziałbym, że char (40). Trudno powiedzieć bez przeprowadzenia kilku testów z językiem i sprzętem, którego będziesz używać, i zobacz, co najbardziej Ci odpowiada.
Francesco Casula,
1
Przypuszczam, że jeśli robisz coś innego niż wybieranie z miejsca, w którym unhex (hash) = hash, aby pobrać pojedynczy wiersz, być może masz rację. Ale utrzymanie indeksu w buforze zajmie w ten sposób dwa razy więcej pamięci.
nickdnk