zoukankan      html  css  js  c++  java
  • 复杂的 Hash 函数组合有意义吗?

    很久以前看到一篇文章,讲某个大网站储存用户口令时,会经过十分复杂的处理。怎么个复杂不记得了,大概就是将口令先 Hash,结果加上一些特殊字符再 Hash,然后中间插入些字符再 Hash、再怎么怎么的。。。看的眼花缭乱。

    当时心想这么复杂应该很安全了吧。事实上即使现在,仍有不少人是这么认为的。所以在储存账号口令时,经常会弄些千奇百怪的组合。

    不过,千奇百怪的 Hash 算法究竟有意义吗?在什么情况下能派上用场?是否有更简单合理的替代方案?这问题先从拖库说起。

    知道算法才能破解

    数据库中的口令,都是以 Hash 形式储存的。拖下数据库后,如果要猜某个账号的明文口令,得通过跑字典的方式:

    for each word in 常用词汇
    	if H(word) == E
    		print "明文:",word
    		exit
    

    不过,光有泄露的数据 E 不够,还得知道算法 H 才能跑的起来。光有 Hash 值,却不知道用的是那种 Hash 算法,仍然无从下手。

    当然很多小网站,数据库和算法在同个系统里,一旦入侵两者都泄露了;但若数据库和算法不在同个系统里,即使能拖库也未必知道算法。

    猜算法

    不过即使搞不到算法,也可以尝试猜测。比如先在网站上注册个账号 —— 例如口令为 123456,然后在泄露的库中,根据用户名找到对应口令的 Hash 值,例如 dd6e5e5918e94d997c686fcebc56922f。

    这时,就可以暴力猜算法了:

    for each fn in 常用算法
    	if fn("123456") == dd6e5e5918e94d997c686fcebc56922f
    		print "算法:", fn
    		exit
    

    不难猜出,fn 为 f(x) = md5(sha256(x))。知道了算法,就可愉快的跑字典了。

    奇怪算法

    这时「奇怪算法」的优势就体现出来了。 如果使用的算法十分奇葩,比如:

    f(x) = md5("hello~" + sha1(sha256(x)) + "world!")
    

    根本不在常用算法里,几乎难以穷举到,于是就能躲过「猜算法」这种攻击方式。

    所以,奇怪的算法是有意义的!

    不过奇怪、奇葩、变态...这些都是人的主观感觉,并不能用理性来衡量。比如说刚才那个算法有多复杂?你只能说很复杂,而难以给出一个准确的程度。

    算法简单,数据复杂

    通过混合拼凑多个函数,来制造复杂程度,终究不是最合适的。

    不妨把复杂转移到数据上,例如上述的 "hello~" 和 "world!",如果换成更长、更没意义、更难猜测的数据,不也能制造复杂吗?

    所以,最终可以把函数精简到只剩一个,取而代之的是复杂的数据,例如:

    f(x) = sha256(x + "18bc0a594ab5f65d868820b238b696e391eabb962e1d15c2c474a04735c1128f")
    

    这串数据称之为密钥。密钥是随机生成的,没有任何意义,并且绝不能对外透露。

    这样,复杂程度就能在密钥空间上体现出来,而不是难以衡量的奇怪函数组合


    不过这里有个疑惑,为什么「密钥」加在原文后面,而不是前面、或者夹在中间?如果仅仅是看着舒服,那还是存在主观因素的。

    HMAC

    事实上,密码学家早已提供支持两个参数的 Hash 用法 —— HMAC,它比简单粗暴的拼接靠谱得多。于是上述可改进成:

    f(x) = hmac_sha256(x, "18bc0a594ab5f65d868820b238b696e391eabb962e1d15c2c474a04735c1128f")
    

    HMAC 第二个参数本身就是 Key 的意思,所以用在这里恰到好处。

    当然,如果不保护好算法以至于很容易泄露,那么无论用奇怪组合还是这种方式,也都无济于事。

    保护算法

    很多人对算法保护的并不好,甚至直接写在了诸如 PHP 脚本里,只要有文件读取权限,就能搞到算法。

    如果稍加隐蔽,例如通过本地服务,并控制好可执行程序的权限,或许就更难找到了。

    更进一步,可以单独部署一台服务器,专门提供 HMAC 计算。通信接口足够简单,简单到几乎不可能出漏洞;并且不开放其他任何服务,只能人工管理。这样,被入侵的可能性就更小了。

    当然,管理员人为泄密也是有可能的。如果要有一个终极方案,或许应该将计算交给一个独立的硬件。这个硬件是个黑盒设备,输入明文、输出 Hash 结果。算法、密钥这些都隐藏在其内部,拆开即自毁,这样管理员也无从知晓。例如 HSM(hardware security module)设备,就能将算法以及密钥进行物理隔离。

      password  |-------------------------|
    ----------->|         黑盒设备         |
                | KEY = ***************** |
    <-----------| hmac_sha(password, KEY) |
        hash    |-------------------------|
    

    其他策略

    如果算法能保证 100% 不泄露,那么加盐、慢 Hash 这些都可以省略了,因为密钥本身就足以对抗暴力破解。

    当然现实中没有绝对的事。如果算法真的泄露了,现有数据的风险就大幅增加。所以本该有的策略还是得有,不能把风险全押在一个点上。

    所以加盐、慢 hash 这些仍然是需要的。最终方案应该类似这样:

    # 业务逻辑
    hash = pbkdf(password, salt, cost...)
                ↓
    ######## 隐蔽的黑盒系统 ########
    hash = hmac(hash, KEY)
    ##############################
                ↓
    # 返回业务
    

    这样即使黑盒算法遭到泄露,破解仍然需要很大成本。

    破解成本

    不过,奇怪算法也有一个优势,那就是破解软件支持程度不高。

    传统的权威算法,早已成为众矢之的,有各种高度优化的破解方案,因此破解速度会非常快;而奇怪算法,则不在优化范围中,因此速度会慢的多。

    所以,在权威算法之后,可以考虑再混合少量奇怪算法。这样,就能再增加一层破解障碍。

    总结

    • 奇怪算法是有意义的,但效果难以衡量

    • HMAC 的密钥需要足够长、足够随机、足够保密

    • 保护好算法,和保护数据库同样重要

  • 相关阅读:
    sqlhelper使用指南
    大三学长带我学习JAVA。作业1. 第1讲.Java.SE入门、JDK的下载与安装、第一个Java程序、Java程序的编译与执行 大三学长带我学习JAVA。作业1.
    pku1201 Intervals
    hdu 1364 king
    pku 3268 Silver Cow Party
    pku 3169 Layout
    hdu 2680 Choose the best route
    hdu 2983
    pku 1716 Integer Intervals
    pku 2387 Til the Cows Come Home
  • 原文地址:https://www.cnblogs.com/index-html/p/complex_algorithm_and_key.html
Copyright © 2011-2022 走看看