在 MySQL 中存储 SHA1 哈希值

Posted

技术标签:

【中文标题】在 MySQL 中存储 SHA1 哈希值【英文标题】:Storing SHA1 hash values in MySQL 【发布时间】:2010-10-11 11:57:15 【问题描述】:

当我想将 SHA1 哈希的结果存储在 mysql 数据库中时,我遇到了一个简单的问题:

我存储哈希结果的 VARCHAR 字段应该多长时间?

【问题讨论】:

如果你只是用谷歌搜索 sha1 点击我感觉很幸运,你应该在***上找到它总是 160 位。 【参考方案1】:

Reference taken from this blog:

以下是哈希算法列表及其所需位大小:

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)
);

【讨论】:

请,pleaseplease实际上不要像这样存储密码。 嘿贝瑞,你能解释一下你的原因吗?详细介绍 存储密码的简单哈希比使用加盐(希望是拉伸的)密码哈希更容易在您的数据库遭到破坏时“提取”密码。推荐阅读:paragonie.com/blog/2016/02/how-safely-store-password-in-2016 @BerryM。一年后阅读这篇文章,并没有想到有人在谈论密码,或者人们是否仍然使用简单的哈希来存储身份验证数据。但他们确实:D【参考方案2】:

我会将VARCHAR 用于可变长度数据,但不能用于固定长度数据。因为 SHA-1 值总是 160 位长,所以VARCHAR 只会浪费an additional byte for the length of the fixed-length field。

我也不会存储 SHA1 返回的值。因为它每个字符只使用 4 位,因此需要 160/4 = 40 个字符。但是如果你使用每个字符 8 位,你只需要一个 160/8 = 20 个字符长的字段。

所以我建议您使用BINARY(20)UNHEX function 将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.56M,而char(40) 需要 64.57M。 InnoDB 引擎。

【讨论】:

在 PostgreSQL 中,这会转化为使用 bytea 字段,对吧? 解决方案很棒,但还有一点是使用 char(40) 和 hexed sha1 - 这使用得更广泛,应用程序代码中的转换问题也会更少。 phpmyadmin 用户注意事项。当将哈希存储为二进制时,phpmyadmin 会将其显示为十六进制字符串,但 pma 将无法在提供的“搜索选项卡”中使用它。仅当您将 UNHEX() 手动添加到 sql 时才有效。 @Gumbo 您可以在一个字节中存储可变数量的字节。您指的是 bytea 类型的存储要求。这是“1 或 4 个字节加上实际的二进制字符串”。 “1 或 4”指的可能是存储数据的长度,因为您不能像使用 varchar 那样使用零字节来结束字符串。这意味着,但手册中没有说明,您最多可以在一个 bytea 中存储 2^(8*4) 或 4+ GB。 postgresql.org/docs/9.0/static/datatype-binary.html 在 postgres 数据库中存储散列可能是最小的 bit 或 bytea 列。 dev.mysql.com/doc/refman/5.5/en/… 在存储 crypt 函数的结果时提供有关性能和存储的信息【参考方案3】:

如果您需要在 sha1 列上建立索引,出于性能原因,我建议使用 CHAR(40)。 在我的情况下,sha1 列是一个电子邮件确认令牌,因此在登录页面上,查询仅使用令牌输入。 在这种情况下,我认为带有 INDEX 的 CHAR(40) 是最好的选择:)

如果要采用这种方式,记得留$raw_output = false。

【讨论】:

为什么不索引 BINARY(20)?那不是一样快,尺寸只有一半吗? 好吧,这大约是 5 年前,但我想我指的是您仍然需要取消十六进制,这会增加一些负载(+ 使应用程序更难维护且更不便携?)。这也取决于您的硬件,如果您的存储空间较少并且速度很慢,最好还是坚持使用二进制(20),否则我会说 char(40)。如果不使用您将使用的语言和硬件进行一些测试,看看什么最适合您,就很难说。 我想如果你做的不是选择 from where unhex(hash) = hash 来获取单行,那么也许你是对的。但是以这种方式保持索引缓冲将占用两倍的内存。【参考方案4】:

在您不总是为用户存储哈希值的情况下(即验证帐户/忘记登录 url),您可能仍希望使用 VARCHAR。一旦用户验证/更改了他们的登录信息,他们就不应该能够使用哈希并且应该没有理由这样做。您可以创建一个单独的表来存储临时哈希 -> 可以删除的用户关联,但我认为大多数人不会费心这样做。

【讨论】:

【参考方案5】:

所以长度介于 10 个 16 位字符和 40 个十六进制数字之间。

在任何情况下,确定您要存储的格式,并根据该格式使字段大小固定。 这样您就不会浪费任何空间。

【讨论】:

【参考方案6】:

sha1 的输出大小为 160 位。即 160/8 == 20 个字符(如果您使用 8 位字符)或 160/16 = 10(如果您使用 16 位字符)。

【讨论】:

假设 8 位二进制字符。如果存储为十六进制,则为 40 个字符。【参考方案7】:

SHA1 哈希的长度为 40 个字符!

【讨论】:

以上是关于在 MySQL 中存储 SHA1 哈希值的主要内容,如果未能解决你的问题,请参考以下文章

git 如何计算文件哈希?

SHA1 哈希值是不是均匀分布?

C#中的SHA1哈希值是否会永远返回给定字符串的相同值?

哈希算法之md5和sha1

Go+ SHA1 哈希值教程(4.12)

Powershell 和 Ruby 中不同的 SHA1 哈希结果