Ce que nous apprenons principalement aujourd'hui, c'est l'utilisation de certaines fonctions d'extension liées au chiffrement de hachage en PHP, et non l'algorithme de hachage. , ce type de cryptage n'est en fait qu'un algorithme de clé plus complexe. Semblable à l'algorithme de hachage, la chaîne que nous saisissons a sa valeur de hachage de hachage correspondante, tout comme une table de hachage. L'essence de ce qui précède est la même que le mappage clé-valeur de hachage. dans des structures de données ordinaires, mais l'algorithme est plus complexe. En fait, tant que vous avez développé PHP pendant un certain temps, vous serez certainement familier avec deux fonctions, qui sont md5() et sha1(). Ces deux fonctions doivent générer respectivement le cryptage de hachage des algorithmes md5 et sha1. Cependant, ce que nous apprenons aujourd’hui est plus complexe que ces deux fonctions, et la forme algorithmique est également plus riche.
Qu'est-ce que l'algorithme de résumé des informations de hachage ?
Habituellement, après avoir saisi un élément de contenu dans une fonction de hachage, la chaîne de hachage renvoyée est le résumé des informations de hachage de la valeur d'entrée. En PHP, la même entrée produira le même résultat, qu'il s'agisse de md5 ou de sha1. Par conséquent, lors de l’enregistrement des informations de mot de passe utilisateur, nous essayons de ne pas utiliser une seule couche de hachage, car cette forme de cryptage peut être déchiffrée par force brute via des tables arc-en-ciel. Nous pouvons hacher le mot de passe en plusieurs couches et ajouter du sel pour compliquer la valeur de hachage.
Bien sûr, les algorithmes de hachage ne se limitent pas à nos md5 et sha1 couramment utilisés, il existe de nombreux autres types d'algorithmes, mais nous ne les utilisons pas couramment. Cependant, les fonctions présentées aujourd'hui ne sont qu'un ensemble de fonctions pouvant effectuer de nombreux types différents de cryptage de hachage. Elles ont été intégrées dans l'environnement par défaut de PHP. Nous n'avons pas besoin d'une extension distincte pour l'utiliser. car notre diversification des données cryptées apporte plus de commodité.
Algorithmes de hachage pris en charge par PHP
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 // ……
Grâce aux fonctions hash_algos() et hash_hmac_algos(), nous pouvons obtenir tous les algorithmes de hachage pris en charge dans l'environnement PHP actuel, et nous pouvons voir le md5 familier et sha1, vous pouvez également voir md2, sha224, ripemd320, fnv1a64 et d'autres algorithmes rarement vus. Ensuite, en parcourant le contenu renvoyé par ces deux fonctions et en utilisant les fonctions hash() et hash_hmac() pour hacher les données et afficher leur contenu, nous pouvons constater que chaque algorithme peut renvoyer avec succès différents résumés d'informations cryptées, et il existe différents chiffres. .
La fonction liée à hmac est une autre forme d'algorithme de hachage de PHP. C'est un algorithme qui nécessite une clé, qui est le troisième paramètre de hash_hmac(). Ce n'est que si le contenu d'entrée est le même et que la clé est la même que le résultat renvoyé sera le même. En d’autres termes, cette fonction peut être utilisée pour les jetons de vérification de transfert d’informations cryptés symétriquement. Par exemple, si l'intercommunication d'interface entre deux systèmes nécessite un jeton fixe, vous pouvez utiliser cette fonction pour y parvenir.
Comparaison avec md5() et sha1()
Cette fonction hash() est si puissante, le contenu qu'elle génère est-il donc le même que celui de 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
Bien sûr, cela ne fait aucun doute. J'ai même l'impression que les deux fonctions md5() et sha1() elles-mêmes sont du sucre syntaxique pour la fonction hash(). Parce que ces deux algorithmes sont si couramment utilisés, PHP encapsule directement les deux fonctions actuelles pour nous, et elles ne nécessitent qu'un seul paramètre, ce qui est très simple et pratique.
Fichier HASH
Dans de nombreux sites de téléchargement, la valeur de hachage du fichier téléchargé nous sera fournie pour effectuer une vérification et une comparaison afin de déterminer si le fichier téléchargé est complet et identique. Il s'agit de l'application du fichier Hash. En fait, pour parler franchement, il s'agit simplement d'un résumé des informations sur le fichier obtenues après hachage du contenu du fichier. Cet ensemble de fonctions est bien entendu également parfaitement pris en charge dans notre PHP.
/ 文件 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
Algorithme HASH de hkdf et pbkdf2
Les deux algorithmes introduits ensuite sont deux algorithmes de hachage spéciaux. Semblable à hmac, mais plus complexe que 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 n'a besoin que d'une seule clé, hash_hkdf() ajoute trois paramètres : la longueur de retour, la chaîne d'informations spécifiques à l'application/au contexte, la valeur du sel et le contenu crypté. C'est un contenu crypté binaire, ne semble-t-il pas très élevé -fin? Hash_pbkdf2() ajoute trois paramètres : la valeur du sel, le nombre d'itérations et la longueur des données. C'est également une bonne aide pour le cryptage des mots de passe. Mais relativement parlant, leur utilisation est plus compliquée. S'il s'agit d'un mot de passe avec des exigences de sécurité très élevées, vous pouvez utiliser ces deux fonctions.
La fonction Hash_equals() effectue une comparaison de hachage
PHP nous fournit également une fonction pour comparer si les valeurs de hachage sont égales. Certains amis peuvent demander, puisque les informations récapitulatives sous forme de chaîne sont renvoyées, ne suffirait-il pas simplement === Pourquoi avons-nous besoin d'une fonction spéciale pour comparer ? Ne vous inquiétez pas, regardons d'abord le code.
// 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