在 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)
);
【讨论】:
请,please,please实际上不要像这样存储密码。 嘿贝瑞,你能解释一下你的原因吗?详细介绍 存储密码的简单哈希比使用加盐(希望是拉伸的)密码哈希更容易在您的数据库遭到破坏时“提取”密码。推荐阅读: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 哈希值的主要内容,如果未能解决你的问题,请参考以下文章