在MySQL中存储SHA1哈希值


160

我有一个简单的问题,当我想将SHA1哈希的结果存储在MySQL数据库中时发生:

我将散列结果存储在VARCHAR字段中多长时间?


9
如果您只是用Google搜索sha1,请单击“我很幸运”,并且您应该在Wikipedia上,在该网站上您总是可以找到160位。
Tim Matthews,2009年

Answers:


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)需要4456 万,而char(40)需要6457万。 InnoDB发动机。


2
在PostgreSQL中,这将转换为使用bytea字段,对吗?
mvexel 2011年

解决方案很棒,但还有一点需要使用char(40)和sha1的十六进制形式使用-更加广泛地使用它,并且应用程序代码中的转换问题会更少。
亚瑟·库什曼

2
phpmyadmin用户注意事项。当将散列存储为二进制时,phpmyadmin会将其显示为十六进制字符串,但是pma将无法在提供的“搜索”选项卡中使用它。仅当您将UNHEX()手动添加到sql 时才有效。
Timo Huovinen 2014年

2
@Gumbo您可以在bytea中存储可变数量的字节。您指的是bytea类型的存储要求。这是“ 1或4个字节加上实际的二进制字符串”。“ 1或4”所指的可能是所存储数据的长度,因为您不能像使用varchar那样使用零字节结尾字符串。这意味着,但在手册中没有说明,您可以在一个字节存储中最多存储2 ^(8 * 4)或4+ GB。postgresql.org/docs/9.0/static/datatype-binary.html 将散列存储在postgres数据库中可能至少是一点或bytea列。
维克多

2
dev.mysql.com/doc/refman/5.5/en/…在存储crypt函数的结果时提供有关性能和存储的信息
Clocker 2016年


11

从此博客引用:

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

  • MD5 = 128位哈希值。
  • SHA1 = 160位哈希值。
  • SHA224 = 224位哈希值。
  • SHA256 = 256位哈希值。
  • SHA3​​84 = 384位哈希值。
  • SHA512 = 512位哈希值。

使用require 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
请,不要实际存储这样的密码。
Berry M.

嗨,浆果,您能解释一下为什么吗?详细信息
Anvesh

4
如果数据库受到破坏,则存储简单的密码哈希值比使用盐腌(希望扩展)的密码哈希值更容易“提取”密码。建议阅读:paragonie.com/blog/2016/02/how-safely-store-password-in-2016
matt

2
@BerryM。一年后读完这篇文章,一秒钟都没有想到有人在谈论密码,或者人们是否仍然使用简单的哈希来存储身份验证数据。但是他们做到了:D
罗希特·哈兹拉

6

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


假设8位二进制字符。如果存储为十六进制,则为40个字符。
Tyzoid

3

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

无论如何,请确定您要存储的格式,并根据该格式将字段设置为固定大小。这样,您将不会浪费任何空间。


2

如果您不总是为用户存储哈希(即,对帐户进行身份验证/忘记登录网址),则可能仍要使用VARCHAR。一旦用户认证/更改了他们的登录信息,他们就将无法使用哈希并且也没有理由。您可以创建一个单独的表来存储临时哈希->可以删除的用户关联,但我认为大多数人都不会这样做。


2

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

如果要采用此方法,请记住保留$ raw_output = false。


1
为什么不索引BINARY(20)?难道不是那么快并且只有一半大小吗?
nickdnk

好吧,这是大约5年前的事,但我想我指的是您仍然需要进行十六进制处理,这会增加一些负载(+使应用程序更难以维护且移植性更差?)。它也取决于您的硬件,如果存储空间较少并且速度较慢,则最好还是坚持使用binary(20),否则我会说char(40)。如果不使用您要使用的语言和硬件进行测试,很难说出最适合您的语言。
Francesco Casula'2

1
我想,如果您除了从unhex(hash)= hash中选择以获取一行数据之外,还要做其他事情,那么也许您是对的。但是以这种方式保持索引缓冲将占用两倍的内存。
nickdnk
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.