美文网首页虞大胆的PHP之旅程序员@IT·互联网
SHA-1 发生碰撞并不完全代表不安全

SHA-1 发生碰撞并不完全代表不安全

作者: 虞大胆的叽叽喳喳 | 来源:发表于2017-03-28 16:38 被阅读95次

    前一段时间 SHA-1 算法被破解了,大家都在说这个算法太危险了,其实并不是想象的那样,简单的结论就是应该正确的认识这个算法,发生碰撞并不完全代表不安全

    什么是 Hash 函数

    Hash 函数和数据结构中的哈希表其实并不完全一样,数据结构中的哈希表是为了快速查找,而 Hash 函数由于有很多特性,在很多场合都可以使用。那么它有什么特性呢?

    • 单向性,消息经过运算得到的散列值不能反解(这也说明它不是加密算法,因为加密算法需要能够反解)。
    • 不管消息有多大,通过 Hash 函数运算后,散列值的长度都是固定的。
    • 在这个世界上很难发现两个消息具有同样的散列值。
    • 消息只要稍微改变下,散列值就会发生变化。
    • Hash 函数的运算特别快速(针对 MD5、SHA-1 这样的算法来说)。

    其实最重要的特性就是很难发现两个消息具有同样的散列值,Hash 函数理论上要求强抗碰撞性,也正因为如此 Hash 函数被认为是“安全”的。

    Hash 函数在那些场合下使用呢

    因为有了上述的特性,对于我们程序员来说,很多地方都能看到 Hash 函数的影子(确切的说是看到 MD5 或 SHA-1)。

    (1)比如我们在下载软件的时候,总是发现一个值“该软件的 MD5 值是多少多少”,这表示什么意思呢?假如从安全的角度来看,你下载了一个软件,然后对这软件做 Hash 运算,假如发现散列值和下载网站上明文标出的散列值不一样,就说明你可能下载了一个假软件(可能不安全)。

    (2)在 Git 中,任何对象(不管是 blob 对象、树对象等等)都是通过 SHA-1 这个 Hash 函数运算得来的,它认为在一个 Git 仓库中,每个内容都应该是唯一的。

    (3)HTTPS 中也有 Hash 函数的影子,比如浏览器首先会对证书进行 SHA-1 运算得到摘要,然后再和原始证书上的散列值进行比较;还有为了保证发送内容的完整性,HTTPS 中服务器也会使用 SHA-1 对内容进行摘要计算,然后通过对称加密算法运算后发送给用户。

    (4)其实对于技术开发来说,Hash 函数用的比较多的地方就是对口令进行加密,Hash 函数本身和口令加密没有任何关系,但由于它具备的一些特性,确实可以用来加密,用 cryptographic hash functions 来进行标识比较好。这一块后面也会重点介绍。

    发生碰撞说明什么

    假如能找到两个不同的消息其散列值一样,那么说明发生了碰撞,这样就代表不安全了,虽然现在 Google 发现 SHA-1 存在碰撞(其实以前就说 SHA-1 不安全,等真正产生的时候大家才如令大敌)。其实碰撞不完全代表不安全,首先要产生碰撞需要话费大量的运算时间和空间,Google spent 6500 CPU years and 110 GPU years to convince everyone we need to stop using SHA-1 for security critical applications.;其次一个系统真正是否安全取决你如何使用 Hash 函数以及原始消息是如何组成的。

    比如在 Git 中,并不是对文件内容直接做 SHA-1 运算,运算的内容不仅包括文件内容,还包括了很多元信息,而想要伪造这些本身很困难,所以现实情况下,SHA-1 情况并没有那么严重。

    cryptographic hash functions

    这是我想重点描述的一块,如何安全的存储用户口令,观点就是 Hash 函数并没有错,错在于你可能并不理解它。

    对于开发者来说要明白 Hash 函数的原理,寻找存储口令的最佳实践。

    即使我们并不明白密码学,也要学会如何正确的使用 Hash 函数存储口令。下面的 5 个观点希望你能做到,做的越多口令可能就更安全。

    (1)假设你存储用户密码的数据库被脱库了,这样才能通过字典攻击和暴力攻击获取用户口令。假如完全通过 HTTP 的暴力攻击去获取用户密码,很大程度上会被当作 DDOS 攻击而屏蔽掉,你任何校验口令的程序需要有保护机制。

    (2)你的口令应该足够“安全”,最好是 ASCII 的无序组合,因为口令长度增大 1 位,攻击者花费的时间就更长。

    (3)在使用 SHA-1 等 Hash 函数的时候,一定要在口令后面附上盐值,盐值一定要足够唯一,而且盐值一定不要和用户数据库(包含密码)保存在一起,盐值主要是为了防止彩虹表攻击,加大口令破解难度。

    (4)MD5、SHA-1 这样的 Hash 函数运算特别快,所以不适合用作加密口令,因为速度越快,攻击者破解花费的时间就越少。所以应该选择运算相对慢的函数,比如 Bcrypt 算法。

    (5)Bcrypt 算法能够让运算减慢速度,原因在于有个迭代因子的概念,另外个好处就是算法本身会存储盐值,不用额外在别的地方存储(这本身就很危险),所以提倡使用。假如你是 PHP 开发者,请直接使用 Password Hashing 扩展,其对 Bcrypt 做了透明处理。

    假如你想自己实现 Bcrypt(对 Crypt 的一个封装),可以使用下列的 PHP 代码:

    <?php
    
    class PassHash {
     
        // blowfish ,高于 PHP 5.3.7
        private static $algo = '$2a$';
     
        public static function unique_salt() {
            return substr(sha1(mt_rand()),0,22);
        }
     
        public static function hash($password,$cost=10) {
            return crypt($password,self::$algo .$cost . self::unique_salt());
        }
     
        public static function check_password($hash, $password) {
    
            $full_salt = substr($hash, 0, 29);
            $new_hash = crypt($password, $full_salt);
            return ($hash == $new_hash);
        }
    }
    
    $user_pwd = "mypassword";
    $pass_hash = PassHash::hash($user_pwd,5);
    var_dump(PassHash::check_password($pass_hash, $user_pwd));
    

    相关文章

      网友评论

        本文标题:SHA-1 发生碰撞并不完全代表不安全

        本文链接:https://www.haomeiwen.com/subject/kdnjottx.html