Was wir heute hauptsächlich lernen, ist die Verwendung einiger Erweiterungsfunktionen im Zusammenhang mit der Hash-Hash-Verschlüsselung in PHP und nicht mit dem Hash-Algorithmus. Diese Art der Verschlüsselung ist eigentlich nur eine komplexere Der Schlüsselalgorithmus ähnelt dem Hash-Algorithmus, da die von uns eingegebene Zeichenfolge genau wie eine Hash-Tabelle mit der Hash-Schlüsselwertzuordnung in einer gewöhnlichen Datenstruktur identisch ist Das heißt, der Algorithmus ist nur komplizierter. Tatsächlich werden Sie, sofern Sie eine Zeit lang PHP-Entwicklung betrieben haben, auf jeden Fall mit zwei Funktionen vertraut sein, nämlich md5() und sha1(). Diese beiden Funktionen dienen dazu, die Hash-Verschlüsselung der MD5- bzw. SHA1-Algorithmen zu generieren. Was wir heute lernen, ist jedoch komplexer als diese beiden Funktionen und auch die Form des Algorithmus ist umfangreicher.
Was ist ein Hash-Information-Digest-Algorithmus?
Nachdem wir einen Inhalt in eine Hash-Funktion eingegeben haben, ist die zurückgegebene Hash-Zeichenfolge normalerweise der Hash-Information-Digest des Eingabewerts. In PHP führt die gleiche Eingabe zum gleichen Ergebnis, egal ob md5 oder sha1. Daher versuchen wir beim Speichern von Benutzerpasswortinformationen, nicht nur eine Hash-Ebene zu verwenden, da diese Form der Verschlüsselung durch Brute-Force-Methode über Rainbow Tables geknackt werden kann. Wir können das Passwort in mehreren Ebenen hashen und Salt hinzufügen, um den Hash-Wert zu komplizieren.
Natürlich sind Hash-Algorithmen nicht auf die häufig verwendeten MD5- und SHA1-Algorithmen beschränkt. Es gibt viele andere Arten von Algorithmen, die wir jedoch nicht häufig verwenden. Bei den heute eingeführten Funktionen handelt es sich jedoch lediglich um eine Reihe von Funktionen, die viele verschiedene Arten der Hash-Verschlüsselung ausführen können. Sie wurden in die Standardumgebung von PHP integriert. Auf diese Weise ist keine separate Erweiterung erforderlich Denn die Diversifizierung unserer verschlüsselten Daten bringt mehr Komfort.
Von PHP unterstützte Hash-Algorithmen
print_r(hash_algos()); // Array // ( // [0] => md2 // [1] => md4 // [2] => md5 // [3] => sha1 // [4] => sha224 // [5] => sha256 // [6] => sha384 // [7] => sha512/224 // [8] => sha512/256 // [9] => sha512 // [10] => sha3-224 // [11] => sha3-256 // [12] => sha3-384 // [13] => sha3-512 // [14] => ripemd128 // [15] => ripemd160 // [16] => ripemd256 // [17] => ripemd320 // [18] => whirlpool // [19] => tiger128,3 // [20] => tiger160,3 // [21] => tiger192,3 // [22] => tiger128,4 // [23] => tiger160,4 // [24] => tiger192,4 // [25] => snefru // [26] => snefru256 // [27] => gost // [28] => gost-crypto // [29] => adler32 // [30] => crc32 // [31] => crc32b // [32] => fnv132 // [33] => fnv1a32 // [34] => fnv164 // [35] => fnv1a64 // [36] => joaat // [37] => haval128,3 // [38] => haval160,3 // [39] => haval192,3 // [40] => haval224,3 // [41] => haval256,3 // [42] => haval128,4 // [43] => haval160,4 // [44] => haval192,4 // [45] => haval224,4 // [46] => haval256,4 // [47] => haval128,5 // [48] => haval160,5 // [49] => haval192,5 // [50] => haval224,5 // [51] => haval256,5 // ) $data = "我们来测试一下Hash算法!"; foreach (hash_algos() as $v) { $r = hash($v, $data); echo $v, ':', strlen($r), '::', $r, PHP_EOL; } // md2:32::3d63d5f6ce9f03379fb3ae5e1436bf08 // md4:32::e9dc8afa241bae1bccb7c58d4de8b14d // md5:32::2801b208ec396a2fc80225466e17acac // sha1:40::0f029efe9f1115e401b781de77bf1d469ecee6a9 // sha224:56::3faf937348ec54936be13b63feee846d741f8391be0a62b4d5bbb2c8 // sha256:64::8f0bbe9288f6dfd2c6d526a08b1fed61352c894ce0337c4e432d97570ae521e3 // sha384:96::3d7d51e05076b20f07dad295b161854d769808b54b784909901784f2e76db212612ebe6fe56c6d014b20bd97e5434658 // …… foreach (hash_hmac_algos() as $v) { $r = hash_hmac($v, $data, 'secret'); echo $v, ':', strlen($r), '::', $r, PHP_EOL; } // md2:32::70933e963edd0dcd4666ab9253a55a12 // md4:32::d2eda43ee4fab5afc067fd63ae6390f1 // md5:32::68bf5963e1426a1feff8149da0d0b88d // sha1:40::504bc44704b48ac75435cdccf81e0f056bac98ba // sha224:56::8beaf35baedc2cd5725c760ec77d119e3373f14953c74818f1243f69 // sha256:64::23f2e6685fe368dd3ebe36e1d3d672ce8306500366ba0e8a19467c94e13ddace // sha384:96::740ce7488856737ed57d7b0d1224d053905661ffca083c02c6a9a9230499a4a3d96ff0a951b8d03dbafeeeb5c84a65a6 // ……
Über die Funktionen hash_algos() und hash_hmac_algos() können wir alle in der aktuellen PHP-Umgebung unterstützten Hash-Algorithmen abrufen, sowie md2 und sha224 , reifemd320, fnv1a64 und andere selten gesehene Algorithmen. Indem wir dann den von diesen beiden Funktionen zurückgegebenen Inhalt durchlaufen und die Funktionen hash() und hash_hmac() verwenden, um die Daten zu hashen und ihren Inhalt anzuzeigen, können wir feststellen, dass jeder Algorithmus erfolgreich unterschiedliche verschlüsselte Informationsauszüge zurückgeben kann und Es gibt unterschiedliche Ziffern . Die
hmac-bezogene Funktion ist eine andere Form des Hash-Algorithmus von PHP. Es handelt sich um einen Algorithmus, der einen Schlüssel erfordert, der der dritte Parameter von hash_hmac() ist. Nur wenn der Eingabeinhalt derselbe ist und der Schlüssel derselbe ist, ist das zurückgegebene Ergebnis dasselbe. Mit anderen Worten: Diese Funktion kann für symmetrisch verschlüsselte Verifizierungstoken für die Informationsübertragung verwendet werden. Wenn beispielsweise die Schnittstellenkommunikation zwischen zwei Systemen ein festes Token erfordert, können Sie dies mit dieser Funktion erreichen.
Vergleich mit md5() und sha1()
Diese hash()-Funktion ist so leistungsstark, ist der Inhalt, den sie generiert, derselbe wie md5?
// 与 md5 sha1 函数对比 echo hash('md5', '我们来测试一下Hash算法!'), PHP_EOL; echo md5('我们来测试一下Hash算法!'), PHP_EOL; // 2801b208ec396a2fc80225466e17acac // 2801b208ec396a2fc80225466e17acac echo hash('sha1', '我们来测试一下Hash算法!'), PHP_EOL; echo sha1('我们来测试一下Hash算法!'), PHP_EOL; // 0f029efe9f1115e401b781de77bf1d469ecee6a9 // 0f029efe9f1115e401b781de77bf1d469ecee6a9 echo hash('fnv164', '我们来测试一下Hash算法!'), PHP_EOL; // b25bd7371f08cea4
Daran gibt es natürlich keinen Zweifel. Ich habe sogar das Gefühl, dass die beiden Funktionen md5() und sha1() selbst syntaktischer Zucker für die Funktion hash() sind. Da diese beiden Algorithmen so häufig verwendet werden, kapselt PHP die beiden aktuellen Funktionen direkt für uns und erfordert nur einen Parameter, was sehr einfach und praktisch ist.
Datei-HASH
Auf vielen Download-Sites wird uns der Hash-Wert der heruntergeladenen Datei zur Verfügung gestellt, damit wir ihn überprüfen und vergleichen können, um festzustellen, ob die heruntergeladene Datei vollständig und identisch ist. Dies ist die Anwendung von Datei-Hash. Um es ganz klar auszudrücken: Es handelt sich lediglich um eine Zusammenfassung der Informationen über die Datei, die nach dem Hashing des Dateiinhalts erhalten werden. Selbstverständlich wird dieser Funktionsumfang auch in unserem PHP perfekt unterstützt.
/ 文件 HASH echo hash_file('md5', './create-phar.php'), PHP_EOL; echo md5_file('./create-phar.php'), PHP_EOL; // ba7833e3f6375c1101fb4f1d130cf3d3 // ba7833e3f6375c1101fb4f1d130cf3d3 echo hash_hmac_file('md5', './create-phar.php', 'secret'), PHP_EOL; // 05d1f8eb7683e190340c04fc43eba9db
HASH-Algorithmus von hkdf und pbkdf2
Die beiden als nächstes vorgestellten Algorithmen sind zwei spezielle Hash-Algorithmen. Ähnlich wie hmac, aber komplexer als hmac.
// hkdf pbkdf2 算法 // 算法 明文密码(原始二进制) 输出长度 应用程序/特定于上下文的信息字符串 salt值 $hkdf1 = hash_hkdf('sha256', '123456', 32, 'aes-256-encryption', random_bytes(2)); $hkdf2 = hash_hkdf('sha256', '123456', 32, 'sha-256-authentication', random_bytes(2)); var_dump($hkdf1); var_dump($hkdf2); // string(32) "ԇ`q��X�l� // f�yð����}Ozb+�" // string(32) "%���]�+̀�\JdG��HL��GK�� // -" // 算法 明文密码 salt值 迭代次数 数据长度 echo hash_pbkdf2("sha256", '123456', random_bytes(2), 1000, 20), PHP_EOL; // e27156f9a6e2c55f3b72
hmac benötigt nur einen Schlüssel, hash_hkdf() fügt drei Parameter hinzu: Rückgabelänge, anwendungs-/kontextspezifische Informationszeichenfolge und Salt-Wert, und der verschlüsselte Inhalt ist eine binäre Verschlüsselung. Der Inhalt fühlt sich nicht sehr hochwertig an ? Hash_pbkdf2() fügt drei Parameter hinzu: Salt-Wert, Anzahl der Iterationen und Datenlänge. Es ist auch ein guter Helfer für die Passwortverschlüsselung. Relativ gesehen ist ihre Verwendung jedoch komplizierter. Handelt es sich um ein Passwort mit sehr hohen Sicherheitsanforderungen, können Sie diese beiden Funktionen nutzen. Die Funktion
hash_equals() führt einen Hash-Vergleich durch.
PHP stellt uns auch eine Funktion zur Verfügung, um zu vergleichen, ob Hash-Werte gleich sind. Einige Freunde fragen sich vielleicht, ob es nicht ausreichen würde, einfach === zu verwenden, da die zusammenfassenden Informationen in Form einer Zeichenfolge zurückgegeben werden. Warum benötigen wir zum Vergleichen eine spezielle Funktion? Keine Sorge, schauen wir uns zuerst den Code an.
// hash_equals 比较函数 $v1 = hash('md5', '测试对比'); $v2 = hash('md5', '测试对比'); $v3 = hash('md5', '测试对比1'); // 比较两个字符串,无论它们是否相等,本函数的时间消耗是恒定的 // 本函数可以用在需要防止时序攻击的字符串比较场景中, 例如,可以用在比较 crypt() 密码哈希值的场景 var_dump(hash_equals($v1, $v2)); var_dump(hash_equals($v1, $v3)); // bool(true) // bool(false)
我在注释中已经写得很清楚了,hash_equals() 函数主要是可以防止时序攻击。一般来说,这个时序攻击就是根据你的系统运行时间长短来判断你的系统中使用了什么函数或者功能,这都是非常厉害的黑客高手玩的东西。比如说,我们比较用户密码的时候,假设是一位一位的进行比较,那么如果第一个字符错了信息很快就会返回,而如果比较到最后一个才错的时候,程序运行时间就会长很多,黑客就可以根据这个时长来判断当前暴力破解的内容是否一步步达到目标,也让破解难度逐步下降。(普通的字符串比较 === 就是基于位移的)。而 hash_equals() 则是不管怎么比较,相同的 Hash 算法长度的内容返回的时间都是相同的。OpenSSL 、 OpenSSH 等软件都曾出现过这种类似的时序攻击漏洞!
当然,这个我们只做了解即可,同样也是对于安全性有特殊要求的一些项目,就可以使用这个函数来避免出现这种时序攻击的漏洞提高系统安全性。
增量 Hash 操作
最后我们要学习的是一套增量 Hash 的操作函数。其实对于字符串来说,大部分情况下我们直接将字符串拼接好再 Hash 就可以了,并不太需要增量 Hash 的能力。但是如果是对于多个文件或者读写流来说,想要获得多文件的 Hash 值,就可以使用这一套增量 Hash 函数来进行操作了。
// 增量 HASH $fp = tmpfile(); fwrite($fp, '初始化一个流文件'); rewind($fp); $h1 = hash_init('md5'); // 开始增量 Hash hash_update($h1, '测试增量'); // 普通字符串 hash_update_file($h1, './create-phar.php'); // 文件 hash_update_stream($h1, $fp); // 流 $v1 = hash_final($h1); // 结束 Hash 返回结果 echo $v1, PHP_EOL; // 373df6cc50a1d7cd53608208e91be1e7 $h2 = hash_init('md5', HASH_HMAC, 'secret'); // 使用 HMAC 算法的增量 HASH hash_update($h2, '测试增量'); hash_update_file($h2, './create-phar.php'); hash_update_stream($h2, $fp); $v2 = hash_final($h2); echo $v2, PHP_EOL; // 34857ee5d8b573f6ee9ee20723470ea4
我们使用 hash_init() 来获得一个增量 Hash 操作句柄并指定好加密算法。然后使用 hash_update() 添加字符串、使用 hash_update_file() 增加文件内容,使用 hash_update_stream() 来增加流内容,最后使用 hash_final() 结束句柄操作进行 Hash 计算并返回结果值。得到的结果值就是包含字符串、文件和流内容一起 Hash 的结果。
推荐学习:《PHP视频教程》
总结
说实话,在没有学习今天的内容之前,我也一直以为 PHP 里面只有 md5 和 sha1 这两种 Hash 算法呢。这回真是大开了眼界,我们不仅拥有丰富的算法库,而且还有很多方便的操作函数能够帮助我们方便的使用这些算法,不多说了,学习继续!
测试代码:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202007/source/PHP%E7%9A%84Hash%E4%BF%A1%E6%81%AF%E6%91%98%E8%A6%81%E6%89%A9%E5%B1%95%E6%A1%86%E6%9E%B6.php