V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
Semidio
V2EX  ›  问与答

使用MD5来加密数据的安全隐患?

  •  
  •   Semidio · 2012-01-15 12:51:18 +08:00 · 5800 次点击
    这是一个创建于 4699 天前的主题,其中的信息可能已经有所发展或是发生改变。
    MD5本来就不是一个加密算法,它是用于确保信息传输完整一致的算法。
    先不提碰撞的问题,虽然MD5的编码会使原文变成不可逆的Hash编码,但这是在原文长度无限制的情况下,如果原文长度有限,例如密码(一般不超过16位),那么一个MD5编码就可以对应到有限多个原文,而且长度越短,可以对应到的原文越少。
    而且还可以通过事先计算好对应码表,之后只需对照即可。即使使用(原文+固定值)再MD5,只要新建多个账号,查看其保存的MD5值,很容易就可以找到规律,获得这个固定值的数值,从而破解密码的加密。
    使用随机值的话,也只要新建更多的账号,根据原文密码和MD5解开后的数值对照,总可以找到其内在随机规律,从而破解加密。
    按照现在的电脑运行速度,这些运算应当都不是什么负担了。
    是不是以后用MD5加密的数据都不安全了呢?
    17 条回复    1970-01-01 08:00:00 +08:00
    GordianZ
        1
    GordianZ  
    MOD
       2012-01-15 12:57:37 +08:00
    加随机salt是必要的~
    Semidio
        2
    Semidio  
    OP
       2012-01-15 13:07:24 +08:00
    @GordianZ 随机salt只要花时间一样可以破解的出来啊
    skydark
        3
    skydark  
       2012-01-15 14:03:15 +08:00
    黑客通常不是对一个人而是对同一个库中的一批人感兴趣。如使用固定salt,黑客不得不针对该站构造一张单独的彩虹表。如使用随机salt,黑客不得不对每个用户构造单独的彩虹表。
    通常前者在该站有相当价值的情况下是值得的,后者往往入不敷出。破解大多数情况下总是可以的,让破解的成本远大于收益即可。
    Ryans
        4
    Ryans  
       2012-01-15 14:09:14 +08:00
    正如你文中第一句,MD5 本意就不是用来加密的。
    est
        5
    est  
       2012-01-15 14:58:16 +08:00
    > 例如密码(一般不超过16位),那么一个MD5编码就可以对应到有限多个原文

    没看懂这句话。LZ确定你在说散列?
    Hyperion
        6
    Hyperion  
       2012-01-15 16:14:11 +08:00
    @Semidio orz, 我们来算一下...

    密码如果由大小写+数字组成, 一共 (26*2+10)= 62个元素.

    16位密码, 一共就有 (62^16)= 47672401706823533450263330816种组合.

    加一截salt, 每加一位, 就是把幂加了个1.


    找到salt规律? 找吧, 如果掺一段长度20的salt, 那就必须得穷举 3.35815565×10^64 次才能算出来(最坏情况), 就算动用量子计算机这种神器, 也起码得花上很一段时间, 但这不蛋疼么?

    话说回来, 如果把salt当作密钥, 只要用简单的加密算法处理一下的话 -_,-
    Hyperion
        7
    Hyperion  
       2012-01-15 16:15:37 +08:00
    "加一截salt, 每加一位, 就是把幂加了个1. " => "加一截salt, 每加一位, 就是把指数加了个1. "
    yyfearth
        8
    yyfearth  
       2012-01-15 16:40:05 +08:00
    @Semidio md5单纯这个算法确实有些过时,sha1稍微好些,建议使用更加高级的sha256甚至sha512.一方面更加安全,另一方面长度也更长。保存字符串时建议用binary或base64而不是hex,这样就算sha512也很短。原因是,md5和sha1已经可以“碰撞”,不需要找出原来的数据效果相同。
    另外,加salt是必须的。如果加固定的salt,那么通用的彩虹表失效,但是依然可以针对你生成一个彩虹表。加动态的salt,这样彩虹表基本上就费了,因为这样要对每一个salt(就是每个用户)生成一个彩虹表,这样顶多只能对少量用户进行攻击,而且意义不大,不如直接穷举。
    这样安全性就足够了,对于你的几个观点,我不太同意:
    1“即使使用(原文+固定值)再MD5,只要新建多个账号,查看其保存的MD5值,很容易就可以找到规律,获得这个固定值的数值”,如果你的“固定值”足够长(比如1024bit),你根本不可能找出这个“固定值”,除非看到源码。
    2“随机salt只要花时间一样可以破解的出来啊”这个是爆破(字典穷举),加salt只能防彩虹表,对于爆破意义不大。
    任何的加密,只有有足够的时间,一定可以得到,问题是这样,密码的实效已过,破解变得无意义,另外这样的投入远大于产出,黑客不会这么傻。
    yyfearth
        9
    yyfearth  
       2012-01-15 16:42:46 +08:00
    @Ryans “用户密码”是不用所谓的“加密”的,因为密码原码本身不需要存储(对于隐私考虑,也不应该存储),因此你只要验证他“是否一致”不就可以了啊。这样用这些hash,是没有太大问题的,只是要考虑强度问题。
    hq5261984
        10
    hq5261984  
       2012-01-15 23:10:04 +08:00
    @Semidio 如果真按LZ说的那么简单,王晓云的院士就应该给LZ了。不过LZ说的一个观点是对的,任何密码只有给足够的时间就能被破解即伯格夫斯基定律。但是时间本身在密码学领域里就是一个成本,任何密码只有在有效时间内被破解才能称为成功破解。实际上采用LZ所说的暴力破解的方法,时间长短并不取决于加密算法的优越性,更大程度上取决于密码的长度,如果密码为1位,在牛B的加密算法也会在短时间内被暴力破解。
    @yyfearth
    为防止碰撞,现在稍微有点安全需求的数据都是采用变换算法MD5.以PHP为例,我见过的大概有5种。

    变换一:循环MD5

      最容易理解的变换就是对一个密码进行多次的MD5运算。自定义一个函数,它接受$data和$times两个形参,第一个是要加密的密码,第二个是重复加密的次数。

    变换二:密文分割MD5

      尽管用户的密码是不确定的字符串,但是只要经过一次MD5运算后,就会得到一个由32个字符组成的字符串,这时可以再针对这个定长字符串变换。有点BT的算法是,把这段密文分割成若干段,对每段都进行一次MD5运算,然后把这堆密文连成一个超长的字符串,最后再进行一次MD5运算,得到仍然是长度为32位的密文。

    变换三:附加字符串干涉
      在加密过程的一个步骤中,附加一个内容确定的字符串(比如说用户名),干涉被加密的数据。不可以用随机字串,因为这样会使原算法无法重现。这种算法在某些情况下是很具有优势的,比如说用于大量的用户密码加密,可以把用户名作为附加干涉字串,这样攻击者就算知道你的算法,也很难从他们手中的字典中一下子生成海量的对照表,然后大量地破译用户密码,只能有针对性的穷举为数不多的用户。

    变换四:大小写变换干涉
      由于PHP所提供的md5()函数返回的密文中的英文字母全部都是小写的,因此我们可以把它们全部转为大写,然后再进行一次MD5运算。

    变换五:字符串次序干涉
      把MD5运算后的密文字符串的顺序调转后,再进行一次MD5运算。

    还有更BT的采用5种混合玩法,但是服务器开销很大。只能用BT来形容。
    Hyperion
        11
    Hyperion  
       2012-01-15 23:46:50 +08:00
    @hq5261984 曾经见过把原文用RC4先跑一遍, 然后送去MD5的. 速度快, 效率高.
    yyfearth
        12
    yyfearth  
       2012-01-16 11:07:49 +08:00
    @hq5261984 随机的salt可以分开或者合并保存。而且仅仅在数据库的时候使用。
    比如 hash=sha(password+salt)+salt,在验证的时候,则要把这个salt取出来,进行校验。
    这样,即使db被盗,彩虹表也没有用,只能针对某个用户单独建表就划不来了。
    用username可以作为这个salt的一部分,不过由于username长度不是很长,而且不够随机,而且在db没有泄露的时候就已经已知了。
    如果是客户端hash,就不能随机salt,除非吧salt也传过去(可以用timestamp,然后校验2者)
    服务器端用于持久化,就可以考虑加入随机salt,可以吧这个salt存为一独立字段,或者像上面一样,合并在一起。
    Hyperion
        13
    Hyperion  
       2012-01-17 13:35:30 +08:00
    @yyfearth 其实只要salt够长, 暴露出来也没什么的吧? 如果安全性要求需要, 可以在客户端计算hash的时候加进一次性的salt, salt由服务端生成.
    Hyperion
        14
    Hyperion  
       2012-01-17 13:42:33 +08:00
    @yyfearth 啊, 一次性salt的方案有很大漏洞, 设想的不对... orz 没想清楚就发出来了
    yyfearth
        15
    yyfearth  
       2012-01-17 13:53:14 +08:00
    @Hyperion 一次性salt,不管再怎么长,如果泄露出来的话,只要针对性的建立一次彩虹表,就ok了。当然,不泄露的话,salt长点问题也不大。
    对于salt的时候,分2个情况,一个是存储密码的时候,一个是校验密码的时候。2个时候可以采用不同的策略。
    est
        16
    est  
       2012-01-17 13:57:00 +08:00
    > 只要新建多个账号,查看其保存的MD5值,很容易就可以找到规律,获得这个固定值的数值,从而破解密码的加密。

    这句话也太牛了。
    Hyperion
        17
    Hyperion  
       2012-01-17 14:23:05 +08:00
    @yyfearth 嗯, 戳下发送的一瞬间突然反应过来了...
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2361 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 16:11 · PVG 00:11 · LAX 08:11 · JFK 11:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.