Хранение хеш-значений SHA1 в MySQL

160

У меня есть простой вопрос, который возник, когда я хотел сохранить результат хэша SHA1 в базе данных MySQL:

Как долго должно быть поле VARCHAR, в котором я храню результат хеширования?

niklasfi
источник
9
Если вы только что прогуглили Sha1 клик, мне повезло, и вы должны быть в Википедии, где вы всегда найдете 160 бит.
Тим Мэтьюз

Ответы:

315

Я бы использовал VARCHARдля данных переменной длины, но не с данными фиксированной длины. Поскольку значение SHA-1 всегда имеет длину 160 битов, VARCHARон просто тратит дополнительный байт на длину поля фиксированной длины .

И я также не буду хранить значение, SHA1которое возвращается. Потому что он использует только 4 бита на символ и, следовательно, потребует 160/4 = 40 символов. Но если вы используете 8 бит на символ, вам потребуется только поле длиной 160/8 = 20 символов.

Поэтому я рекомендую вам использовать BINARY(20)и UNHEXфункцию для преобразования SHA1значения в двоичное.

Я сравнил требования к хранилищу для BINARY(20)и 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
);

С миллиона записей binary(20)уходит 44,56 млн, а char(40)уходит 64,57 млн. InnoDBдвигатель.

гумбо
источник
2
В PostgreSQL это будет означать использование поля bytea, верно?
mvexel
Решение отличное, но есть еще один момент - использовать char (40) с шестнадцатеричным sha1 - он используется гораздо более широко, и в коде приложения будет меньше проблем с преобразованием.
Артур Кушман
2
Примечание для пользователей phpmyadmin. При хранении хеша в двоичном виде phpmyadmin отобразит его в виде шестнадцатеричной строки, но pma не сможет использовать его в предоставленной «вкладке поиска». Будет работать, только если вы добавите UNHEX()вручную в SQL.
Тимо Хуовинен
2
@Gumbo Вы можете хранить переменное количество байтов в байте. Вы ссылаетесь на требования к хранилищу типа bytea. Это "1 или 4 байта плюс фактическая двоичная строка". То, что означает «1 или 4», может быть длиной хранимых данных, поскольку вы не можете использовать нулевой байт для завершения строки, как вы делаете с varchar. Это подразумевает, но не указано в руководстве, что вы можете хранить до 2 ^ (8 * 4) или 4+ гигабайт в байтах. postgresql.org/docs/9.0/static/datatype-binary.html Хранение хеша в базе данных postgres, вероятно, будет наименьшим в виде битового или байтового столбца.
Виктор
2
dev.mysql.com/doc/refman/5.5/en/… предоставляет информацию о производительности и хранении при хранении результатов функций
шифрования
11

Ссылка взята из этого блога:

Ниже приведен список алгоритма хеширования вместе с размером требуемого бита:

  • MD5 = 128-битное хеш-значение.
  • SHA1 = 160-битное хеш-значение.
  • SHA224 = 224-битное хеш-значение.
  • SHA256 = 256-битное хеш-значение.
  • SHA384 = 384-битное хеш-значение.
  • SHA512 = 512-битное хеш-значение.

Создан один пример таблицы с требованием 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
источник
10
Пожалуйста, пожалуйста , пожалуйста , не храните такие пароли.
Берри М.
Эй, Берри, можешь объяснить, ПОЧЕМУ? в деталях
Anvesh
4
Хранение простых хэшей паролей значительно упрощает «извлечение» паролей, если ваша база данных взломана, чем если вы используете соленый (надеюсь, растянутый) хэш пароля. Рекомендуемая литература: paragonie.com/blog/2016/02/how-safely-store-password-in-2016
матовый
2
@BerryM. прочитав это год спустя, ни секунды не думал, что кто-то говорит о паролях или что люди все еще используют простой хэш для хранения данных аутентификации. Но они делают: D
Рохит Хазра
6

Выходной размер sha1 составляет 160 бит. Это 160/8 == 20 символов (если вы используете 8-разрядные символы) или 160/16 = 10 (если вы используете 16-разрядные символы).

inazaruk
источник
Предполагая 8-битные двоичные символы. 40 символов, если они хранятся в шестнадцатеричном виде.
Tyzoid
3

Таким образом, длина составляет от 10 16-битных символов до 40 шестнадцатеричных цифр.

В любом случае выберите формат, который вы собираетесь хранить, и установите для поля фиксированный размер на основе этого формата. Таким образом, у вас не будет пустого места.

Дуглас Лидер
источник
2

Вы все еще можете использовать VARCHAR в тех случаях, когда вы не всегда сохраняете хеш для пользователя (то есть аутентификация учетных записей / забытый URL-адрес входа в систему). Как только пользователь подтвердил подлинность / изменил свою регистрационную информацию, он не сможет использовать хэш и не будет иметь для этого никаких оснований. Вы можете создать отдельную таблицу для хранения временного хеша -> ассоциации пользователей, которые могут быть удалены, но я не думаю, что большинство людей делают это.

Кит Харти
источник
2

Если вам нужен индекс для столбца sha1, я предлагаю CHAR (40) по соображениям производительности. В моем случае столбец sha1 является токеном подтверждения электронной почты, поэтому на целевую страницу запрос поступает только с токеном. В этом случае CHAR (40) с INDEX, на мой взгляд, является лучшим выбором :)

Если вы хотите принять этот метод, не забудьте оставить $ raw_output = false.

Франческо Касула
источник
1
Почему бы вам не индексировать BINARY (20)? Разве это не было бы так же быстро и вдвое больше по размеру?
nickdnk
Ну, это ~ 5 лет назад, но я думаю, что я имел в виду тот факт, что вам все еще нужно unhex, который добавляет некоторую нагрузку (+ делает приложение более сложным в обслуживании и менее переносимым?). Это также зависит от вашего аппаратного обеспечения: если у вас меньше места для хранения, и оно медленное, вероятно, лучше придерживаться двоичного кода (20), иначе я бы сказал char (40). Трудно сказать, не выполняя некоторые тесты с языком и оборудованием, которое вы будете использовать, и посмотрите, что вам больше подходит.
Франческо
1
Я полагаю, если вы делаете что-то кроме выбора, где unhex (hash) = hash, чтобы получить одну строку, то, возможно, вы правы. Но хранение буферизованного индекса потребует вдвое больше памяти.
nickdnk