La fonction crypt () est un choix classique lors de l'utilisation de PHP pour le chiffrement ou la vérification des mots de passe, en particulier avant que Password_Hash () et Password_verify () n'étaient pas disponibles au début. Cependant, de nombreux développeurs rencontreront un problème déroutant lors de l'utilisation de Crypt () : le même code s'exécute dans différents systèmes de fonctionnement ou environnements, mais les résultats sont incohérents et peuvent même entraîner des risques de sécurité. Cet article explorera en profondeur les raisons de ce phénomène et comment éviter ces "fosses".
La fonction Crypt () de PHP est utilisée pour crypter les chaînes à sens unique. Sa logique principale consiste à choisir l'algorithme de cryptage à utiliser en fonction de la "valeur de sel" ( sel ). Cette valeur de sel contrôle non seulement l'algorithme, mais participe également au processus de chiffrement. Par exemple:
echo crypt('password', '$1$mysalt$'); // utiliser MD5 cryptage
Différents préfixes représentent différents algorithmes de chiffrement:
1 $ signifie utiliser le cryptage basé sur MD5
2A $ , 2 ans $ , 2 milliards de dollars signifie utiliser Blowfish (bcrypt)
5 $ signifie utiliser SHA-256
6 $ $ signifie utiliser SHA-512
Bien que Crypt () soit une fonction standard de PHP, son implémentation repose sur la bibliothèque C du système sous-jacent (LIBC). C'est-à-dire que PHP résume uniquement la fonction crypte () au niveau du système. Pour cette raison, il peut y avoir des différences significatives dans le comportement de la crypte () entre différents systèmes d'exploitation, qui sont montrés comme suit:
Tous les systèmes ne prennent pas en charge le même algorithme de chiffrement. Par exemple:
Certaines versions plus anciennes des systèmes MacOS ne prennent en charge que le cryptage traditionnel du DES.
Linux (en particulier les systèmes utilisant GNU LIBC) prend généralement en charge MD5, SHA-256, SHA-512, Blowfish, etc.
Alpine Linux a un support incomplet de certains algorithmes en raison de MUSL LIBC, en particulier Bcrypt.
Cela signifie qu'un script qui s'exécute bien sur Ubuntu à l'aide du cryptage de préfixe de 2 $ $ peut retourner directement * 0 ou * 1 (indiquant l'échec) dans le conteneur alpin, ou renvoyer une chaîne de hachage dans le mauvais format.
Dans certains systèmes, même si le même algorithme est pris en charge, les résultats de cryptage retournés peuvent avoir des formats légèrement différents. Par exemple:
$hash1 = crypt('password', '$2y$10$1234567890123456789012'); // exister Linux supérieur
$hash2 = crypt('password', '$2y$10$1234567890123456789012'); // exister macOS supérieur
Les $ HASH1 et $ HASH2 dans les deux lignes de code ci-dessus peuvent être différents, et même les performances des différentes versions du système seront différentes. Il s'agit d'un risque potentiel de déploiement multiplateforme.
Si aucune valeur de sel appropriée n'est fournie, le comportement de crypte () sera déterminé par le système, qui peut:
Utilisation du DES traditionnel
Utilisez un algorithme de hachage par défaut
Échec de retour directement
Cela signifie que lorsque l'algorithme et la valeur de sel ne sont pas explicitement spécifiés dans le code, le comportement du programme dépend entièrement de l'implémentation du système et est extrêmement peu fiable.
Un développeur a utilisé une fois Crypt () dans le framework Laravel pour crypter manuellement les mots de passe utilisateur et les stocker dans la base de données. Le code s'exécute normalement dans l'environnement de développement Ubuntu local. Cependant, après le déploiement dans un conteneur Docker basé sur Alpine, la connexion de l'utilisateur échoue toujours. La raison en est que Crypt () dans Alpine ne prend pas en charge l'algorithme de 2 $ $ bcrypt qu'ils utilisent, ce qui entraîne le hachage généré illégal.
Pour éviter ces problèmes de compatibilité et de portabilité, il est recommandé:
Ces fonctions ont été introduites depuis PHP 5.5 et sont mieux encapsulées sur l'implémentation sous-jacente, sans s'appuyer sur le comportement crypte () du système. Exemple de code:
$hash = password_hash('mypassword', PASSWORD_BCRYPT);
if (password_verify('mypassword', $hash)) {
echo 'Mot de passe correct';
}
Cette méthode prend non seulement la sélection automatique de l'algorithme optimal, mais gère également les améliorations de paramètres de chiffrement (telles que le coût), qui est la pratique la plus recommandée à l'heure actuelle.
Et assurez-vous que l'environnement cible prend en charge l'algorithme, par exemple:
$salt = '$2y$10$' . substr(str_replace('+', '.', base64_encode(random_bytes(16))), 0, 22);
$hash = crypt('mypassword', $salt);
Assurez-vous de tester le processus de génération et de vérification sur le serveur cible avant le déploiement pour éviter les différences environnementales.
Envisagez d'utiliser des fichiers de configuration ou des variables d'environnement pour contrôler les politiques de chiffrement, ce qui facilite l'ajustement des politiques dans différents environnements.
Bien que Crypt () existe depuis longtemps en PHP, sa dépendance à la plate-forme en fait une option moins fiable, en particulier lorsque le déploiement multiplateforme dans les applications modernes est la norme. La "PIT" rencontrée avec Crypt () est en fait une manifestation de la compatibilité entre les systèmes. La meilleure solution consiste à utiliser des API plus modernes et stables, telles que Password_Hash () .
Si vous maintenez toujours un ancien système ou utilisez Crypt () avec des besoins spéciaux, assurez-vous de tester et de vérifier chaque détail pour vous assurer que tous les environnements de fonctionnement prennent en charge l'algorithme de chiffrement de manière cohérente, sinon vous pouvez monter sur la "grande fosse" de la sécurité ou de la fonctionnalité.
Pour plus de débogage, vous pouvez accéder:
https://m66.net/crypt-debug-tool (en supposant que la page de l'outil est déployée)
Ne laissez pas un comportement de cryptage différent à travers les systèmes devenir une "bombe temporelle" dans votre projet.