怎么工作 哈希 怎么保护密码
把水果放进榨汁机一打,就成了果汁。光看果汁,没法把放进去的是哪些水果、各放了多少,原样还原出来。安全哈希也差不多:放进一个值,出来一段短短的指纹,但没办法从指纹倒推出原来的值。所以网站不会把你的密码原样存起来,只存这段指纹。
只能往一个方向走
有一种计算,不管放进什么值,都会给出一段固定长度的短指纹,这就叫安全哈希。同一个值放进去,出来的指纹永远一样;哪怕只改一个字,指纹也会变得面目全非,比如把“apple”改成“apples”,算出的两段指纹就毫无相似之处。
最重要的性质是方向。从输入做出指纹很容易,可从指纹倒算出原来的输入,没有办法。水果能变成果汁,果汁却变不回水果。所以它叫单向函数。
用“做指纹”按钮把输入变成指纹。接着点“回去”,会发现路是堵死的。
往前的路一下就通了,往回的路却堵着。这道堵,就是安全哈希的要害:光凭指纹,算不出原来的值。
这个性质用得最多的地方是密码。如果把密码原样存着,谁往存储里看一眼就全知道了。所以要换个办法。
不存密码,存指纹
把密码一字不差地存下来,叫明文存储。这样一来,存储一旦被攻破,甚至只是有人往里看一眼,所有用户的密码就都暴露了。很多人在好几个地方用同一个密码,损失还会蔓延到别的网站。
所以要把密码放进哈希,只存出来的指纹。存储里排着的,就只剩一条条无法还原的指纹。
点“明文存储”和“指纹存储”比一比。明文存储里密码原样可见,指纹存储里只留下无法还原的指纹。
明文存储那边,密码一览无余;指纹存储那边,只剩认不出来的指纹。不过,有了指纹也不能完全放心。攻击者虽然没法倒算指纹,却可以把常见的密码一个个放进哈希,看看有没有哪个算出同样的指纹。
所以专门用于密码的哈希会故意算得很慢,让这种逐个试的办法难以得逞。可如果不存密码,登录时又怎么确认密码对不对呢?
把输入变成指纹来确认
利用“同一个值永远得出同一个指纹”这个性质来确认。登录时用户输入密码,服务器就把这个输入再放进哈希,做出新指纹,再跟存好的指纹比一比。
两个一样,说明输入的是同一个密码,就放行;不一样,就拦下。不用把原来的密码拿出来看,只比指纹就能确认。
选一个输入,点“确认”。输入的指纹和存好的指纹一样就通过,不一样就被挡住。
只有输入正确的密码时,指纹才一致,才通过。只差一个数字的密码,也变成了完全不同的指纹,被挡了下来。只存指纹,用指纹比对来确认,这样没有原文也能分辨对错。
哈希的用处不只在密码上。把下载的文件算出的指纹,和公开的指纹比一比,就能知道文件在传输途中有没有被改过。这正是守护上一课讲的完整性的手段。
和数据单元里的哈希目的不同
哈希这个词,在数据单元里也出现过。那里是把值变成格子号,好快速找到想要的资料。目的是又快又均匀地安排位置,偶尔两个值落进同一个格子,也不算大问题。
安全哈希样子相似,目的却不同:从指纹回不到原来的值,而且要找出算出同一个指纹的两个不同输入,实际上也做不到。
点两边,比一比两种哈希的目的。数据单元里的哈希是为了快找,安全哈希是为了无法还原。
同样叫哈希,数据单元里用它是为了快找,安全领域用它是为了无法还原。目的决定了这件工具需要什么性质。
可见,名字相同的工具,用在不同地方,看重的性质也不一样。格子号和指纹看上去都只是一串短短的数字,背后要求的性质却完全不同。在安全领域,最宝贵的就是无法还原。现在从头到尾理一遍。
小结
归纳起来是这样:安全哈希把输入变成单向的指纹,从指纹回不到输入。所以不存密码本身,只存指纹。登录时把输入再变成指纹,跟存好的指纹比,一样就放行。
这和为了快找而用的数据单元里的哈希不同,是为了无法还原而用的哈希。
依次点要点回顾一下。(单向指纹 → 只存指纹 → 用输入的指纹确认 → 和数据单元里的哈希目的不同)
现在你知道了,不把密码原样留着也能守住它。一段无法还原的指纹,让存储和确认都安全了。谁手里都没有原文,能泄露的秘密也就少了。
不过还剩一个弱点:同一个密码永远得出同一个指纹,两个人用同一个密码,指纹就一样;攻击者还能事先把常见密码的指纹列成一张表。下一课讲盐,也就是用来堵住这个弱点的办法。