Il est actuellement dit que MD5 est partiellement dangereux. Compte tenu de cela, j'aimerais savoir quel mécanisme utiliser pour la protection par mot de passe.
Cette question, Le “double hachage” est-il un mot de passe moins sûr qu'un hachage unique? suggère que hacher plusieurs fois peut être une bonne idée alors que Comment mettre en place une protection par mot de passe pour des fichiers individuels? suggère d'utiliser du sel.
J'utilise PHP. Je veux un système de cryptage des mots de passe sûr et rapide. Le hachage d'un mot de passe un million de fois peut être plus sûr, mais aussi plus lent. Comment atteindre un bon équilibre entre vitesse et sécurité? De plus, je préférerais que le résultat ait un nombre constant de caractères.
De plus, devrais-je stocker deux champs dans la base de données (l'un utilisant MD5 et l'autre utilisant SHA, par exemple)? Cela le rendrait-il plus sûr ou moins sûr?
Au cas où je ne serais pas assez clair, je veux savoir quelle (s) fonction (s) de hachage utiliser et comment choisir un bon sel afin d’avoir un mécanisme de protection de mot de passe rapide et sûr.
Questions connexes qui ne couvrent pas tout à fait ma question:
Quelle est la différence entre SHA et MD5 en PHP
Cryptage par mot de passe simple
Méthodes sécurisées de stockage de clés, mots de passe pour asp.net
Comment implémenteriez-vous les mots de passe salés dans Tomcat 5.5
DISCLAIMER: Cette réponse a été écrite en 2008.
Depuis lors, PHP nous a donné
password_hash
etpassword_verify
et, depuis leur introduction, ils constituent le hachage de mot de passe recommandé. & méthode de vérification.La théorie de la réponse reste néanmoins une bonne lecture.
\0
_ susceptible de nuire gravement à la sécurité.)L'objectif de hachage des mots de passe est simple: empêcher l'accès malveillant aux comptes d'utilisateurs en compromettant la base de données. L'objectif du hachage de mot de passe est donc de dissuader un pirate informatique ou un pirate informatique en leur coûtant trop de temps ou d'argent pour calculer les mots de passe en texte brut. Et le temps et les coûts sont les meilleurs moyens de dissuasion dans votre arsenal.
Une autre raison pour laquelle vous souhaitez un hachage correct et robuste sur un compte d'utilisateur est de vous donner suffisamment de temps pour modifier tous les mots de passe du système. Si votre base de données est compromise, vous aurez besoin de suffisamment de temps pour au moins verrouiller le système, sinon changer tous les mots de passe de la base de données.
Jeremiah Grossman, CTO de Whitehat Security, sur son blog après une récente récupération du mot de passe qui a nécessité la suppression brutale de la protection de son mot de passe:
Fait intéressant, en vivant ce cauchemar, j’ai beaucoup appris que je ne connaissais pas la fêlure des mots de passe, le stockage et la complexité. Je comprends maintenant pourquoi le stockage de mots de passe est encore plus important que sa complexité. Si vous ne savez pas comment votre mot de passe est stocké, alors tout ce dont vous pouvez compter est la complexité. Cela peut être de notoriété publique pour les professionnels du mot de passe et de la crypto, mais pour l'expert moyen d'InfoSec ou de la sécurité Web, j'en doute.
(Souligné par moi.)
Entropie . (Pas que je souscrive pleinement au point de vue de Randall.)
En bref, l'entropie est la variation du mot de passe. Lorsqu'un mot de passe est composé uniquement de lettres romaines minuscules, il ne compte que 26 caractères. Ce n'est pas beaucoup de variation. Les mots de passe alphanumériques sont meilleurs, avec 36 caractères. Mais permettre les majuscules et les minuscules, avec les symboles, équivaut à environ 96 caractères. C'est beaucoup mieux que de simples lettres. L’un des problèmes est que, pour rendre nos mots de passe mémorables, nous insérons des modèles, ce qui réduit l’entropie. Oops!
L'entropie du mot de passe est approximée facilement. L'utilisation de toute la gamme de caractères ascii (environ 96 caractères pouvant être saisis) donne une entropie de 6,6 par caractère, ce qui, avec 8 caractères pour un mot de passe, est encore trop faible (52,679 bits d'entropie) pour une sécurité future. Mais la bonne nouvelle est que des mots de passe plus longs et des mots de passe avec des caractères unicode augmentent vraiment l'entropie d'un mot de passe et le rendent plus difficile à déchiffrer.
Il existe une discussion plus longue sur l'entropie des mots de passe sur le site Crypto StackExchange . Une bonne recherche sur Google donnera également beaucoup de résultats.
Dans les commentaires, j’ai parlé avec @popnoodles, qui a souligné que appliquer une politique de mot de passe de longueur X avec X lettres, nombres, symboles, etc. peut réellement réduire l’entropie en rendant le schéma de mot de passe plus prévisible. Je suis d'accord. Le hasard, aussi aléatoire que possible, est toujours la solution la plus sûre mais la moins mémorable.
Autant que je sache, faire du meilleur mot de passe du monde est un Catch-22. Soit ce n'est pas mémorable, trop prévisible, trop court, trop de caractères unicode (difficile à taper sur un appareil Windows/Mobile), trop long, etc. Aucun mot de passe n'est vraiment suffisant pour nos besoins, nous devons donc les protéger étaient à Fort Knox.
Bcrypt et scrypt sont les meilleures pratiques actuelles. Scrypt sera meilleur que bcrypt dans le temps, mais il n’a pas encore été adopté comme norme par Linux/Unix ou par les serveurs Web, et n’a pas encore publié d’examens approfondis concernant son algorithme. Mais encore, l'avenir de l'algorithme semble prometteur. Si vous travaillez avec Ruby, il existe un scrypt gem qui vous aidera, et Node.js a maintenant son propre package scrypt . Vous pouvez utiliser Scrypt dans PHP via l'extension Scrypt ou l'extension Libsodium (les deux sont disponibles dans PECL).
Je suggère fortement de lire la documentation de fonction cryptée si vous voulez comprendre comment utiliser bcrypt, ou si vous vous trouvez un bienwrapper ou utiliser quelque chose comme PHPASS pour une implémentation plus ancienne. Je recommande un minimum de 12 tours de bcrypt, sinon 15 à 18.
J'ai changé d'avis sur l'utilisation de bcrypt quand j'ai appris que bcrypt n'utilisait que la planification clé de blowfish, avec un mécanisme de coût variable. Ce dernier vous permet d’augmenter le coût de la force brutale d’un mot de passe en augmentant la planification des clés déjà coûteuse de blowfish.
Je ne peux presque plus imaginer cette situation. PHPASS supporte PHP 3.0.18 à 5.3, il est donc utilisable sur presque toutes les installations imaginables - et devrait être utilisé si vous ne le faites pas savoir avec certitude que votre environnement prend en charge bcrypt.
Mais supposons que vous ne puissiez pas utiliser bcrypt ou PHPASS du tout. Quoi alors?
Essayez une implémentation de PDKBF2 avec le nombre maximal de rounds que votre environnement/application/perception de l'utilisateur peut tolérer. Le nombre le plus bas que je recommanderais est 2500 tours. Assurez-vous également d’utiliser hash_hmac () s’il est disponible pour rendre l’opération plus difficile à reproduire.
À venir dans PHP 5.5 est un bibliothèque de protection complète par mot de passe qui élimine toute difficulté liée au travail avec bcrypt. Alors que la plupart d'entre nous sommes coincés avec PHP 5.2 et 5.3 dans la plupart des environnements courants, en particulier les hôtes partagés, @ircmaxell a créé un couche de compatibilité pour la prochaine API compatible avec les versions antérieures PHP 5.3.7.
La puissance de calcul nécessaire pour réellement craquer un mot de passe haché n'existe pas. Le seul moyen pour les ordinateurs de "déchiffrer" un mot de passe est de le recréer et de simuler l'algorithme de hachage utilisé pour le sécuriser. La vitesse du hash est linéairement liée à sa capacité à être brutalement forcée. Pire encore, la plupart des algorithmes de hachage peuvent être facilement parallélisés pour une performance encore plus rapide. C'est pourquoi les systèmes coûteux tels que bcrypt et scrypt sont si importants.
Vous ne pouvez pas éventuellement prévoir toutes les menaces ou voies d’attaque, vous devez donc faire de votre mieux pour protéger vos utilisateurs dès le départ . Sinon, vous pourriez même oublier le fait que vous avez été attaqué jusqu'à ce qu'il soit trop tard ... et que vous soyez responsable . Pour éviter cette situation, agissez d’abord paranoïaque. Attaquez votre propre logiciel (en interne) et tentez de voler les informations d'identification de l'utilisateur, ou de modifier les comptes d'autres utilisateurs ou d'accéder à leurs données. Si vous ne testez pas la sécurité de votre système, vous ne pouvez en vouloir à personne d'autre que vous-même.
Enfin, je ne suis pas un cryptographe. Tout ce que j'ai dit est mon opinion, mais j'estime que c'est basé sur le bon sens commun ... et beaucoup de lecture. Rappelez-vous, soyez aussi paranoïaque que possible, faites en sorte que les choses soient aussi difficiles que possible, puis si vous êtes toujours inquiet, contactez un hacker ou un cryptographe à chapeau blanc pour savoir ce qu'il dit à propos de votre code/système.
Une réponse beaucoup plus courte et plus sûre - n'écrivez pas du tout votre propre mécanisme de mot de passe , utilisez un mécanisme éprouvé.
La plupart des programmeurs n'ont simplement pas l'expertise nécessaire pour écrire du code lié à la cryptographie en toute sécurité sans introduire de vulnérabilités.
Auto-test rapide: Qu'est-ce que l'extension du mot de passe et combien d'itérations devez-vous utiliser? Si vous ne connaissez pas la réponse, vous devez utiliser password_hash()
, car l'extension des mots de passe est désormais une caractéristique essentielle des mécanismes de mot de passe, en raison de la rapidité du processeur et de l'utilisation de GPU et FPGA à craquer. mots de passe à des taux de milliards de suppositions par seconde (avec GPU).
Par exemple, vous pouvez déchiffrer tous les mots de passe Windows à 8 caractères en 6 heures en utilisant 25 GPU installés sur 5 ordinateurs de bureau. C’est brute, c’est-à-dire énumérer et vérifier tous les mots de passe Windows à 8 caractères , y compris les caractères spéciaux, et ne constitue pas une attaque par dictionnaire. C'était en 2012, à partir de 2018, vous pourriez utiliser moins de GPU ou accélérer vos craintes avec 25 GPU.
Il existe également de nombreuses attaques de la table Rainbow sur les mots de passe Windows qui s'exécutent sur des processeurs ordinaires et sont très rapides. Tout cela est dû au fait que Windows est toujours ne salue pas et ne distille pas ses mots de passe, même sous Windows 1 - ne fait pas la même erreur que Microsoft a fait!
Voir aussi:
password_hash()
ou phpass
sont la meilleure solution.Je ne voudrais pas stocker le mot de passe haché de deux manières différentes, car le système est au moins aussi faible que le plus faible des algorithmes de hachage utilisés.
À partir de PHP 5.5, PHP possède des fonctions simples et sécurisées pour le hachage et la vérification des mots de passe, password_hash () et password_verify ()
$password = 'anna';
$hash = password_hash($password, PASSWORD_DEFAULT);
$expensiveHash = password_hash($password, PASSWORD_DEFAULT, array('cost' => 20));
password_verify('anna', $hash); //Returns true
password_verify('anna', $expensiveHash); //Also returns true
password_verify('elsa', $hash); //Returns false
Lorsque password_hash()
est utilisé, il génère un sel aléatoire et l'inclut dans le hachage généré (avec le coût et l'algorithme utilisé.) password_verify()
lit ensuite ce hachage et détermine le sel et la méthode de cryptage utilisés, et le vérifie par rapport au mot de passe en texte clair fourni.
En fournissant le PASSWORD_DEFAULT
, il indique à PHP d'utiliser l'algorithme de hachage par défaut de la version installée de PHP. Quel algorithme signifie-t-on dans le futur dans les versions futures, de sorte qu'il s'agira toujours d'un des algorithmes disponibles les plus puissants.
L'augmentation des coûts (dont la valeur par défaut est 10) rend le hachage plus difficile à manoeuvrer, mais cela signifie également que la génération de hachages et la vérification des mots de passe par rapport à ceux-ci seront plus pénibles pour le processeur de votre serveur.
Notez que même si l'algorithme de hachage par défaut peut changer, les anciens hachages continueront à se vérifier correctement car l'algorithme utilisé est stocké dans le hachage et password_verify()
le détecte.
Bien que la question ait été résolue, je tiens simplement à répéter que les sels utilisés pour le hachage doivent être aléatoires et non pas comme l’adresse e-mail suggérée dans la première réponse.
De plus amples explications sont disponibles sur http://www.pivotalsecurity.com/blog/password-hashing-salt-should-it-be-random/
Récemment, j'ai discuté de la question de savoir si les mots de passe salés avec des bits aléatoires sont plus sécurisés que ceux contenant des sels supposés ou connus. Voyons voir: Si le système qui stocke le mot de passe est compromis, ainsi que celui qui stocke le sel aléatoire, l’attaquant aura accès au hachage ainsi qu’au sel. Par conséquent, peu importe si le sel est aléatoire ou non. L’attaquant peut générer des tables Rainbow pré-calculées pour résoudre le hash. Voici la partie intéressante - il n'est pas si simple de générer des tables pré-calculées. Prenons l'exemple du modèle de sécurité WPA. Votre mot de passe WPA n'est en réalité jamais envoyé à un point d'accès sans fil. Au lieu de cela, il est haché avec votre SSID (le nom de réseau comme Linksys, Dlink, etc.). Une très bonne explication de la façon dont cela fonctionne est ici. Afin de récupérer le mot de passe de hash, vous devez connaître le mot de passe ainsi que le sel (nom du réseau). Church of Wifi a déjà pré-calculé des tables de hachage contenant le top 1000 SSID et environ 1 million de mots de passe. La taille de toutes les tables est d'environ 40 Go. Comme vous pouvez le lire sur leur site, une personne a utilisé 15 baies FGPA pendant 3 jours pour générer ces tables. En supposant que la victime utilise le SSID en tant que "a387csf3" et le mot de passe en tant que "123456", sera-t-il fissuré par ces tables? Non! .. ça ne peut pas. Même si le mot de passe est faible, les tables n’ont pas de hachage pour le SSID a387csf3. C'est la beauté d'avoir du sel au hasard. Cela dissuadera les craqueurs qui prospèrent sur les tables pré-calculées. Peut-il arrêter un pirate informatique déterminé? Probablement pas. Mais l'utilisation de sels aléatoires fournit une couche de défense supplémentaire. Pendant que nous abordons ce sujet, discutons des avantages supplémentaires liés au stockage de sels aléatoires sur un système distinct. Scénario 1: les hachages de mot de passe sont stockés sur le système X et les valeurs de sel utilisées pour le hachage sont stockées sur le système Y. Ces valeurs de sel sont concevables ou connues (par exemple, nom d'utilisateur) Scénario n ° 2: les hachages de mot de passe sont stockés sur le système X et les valeurs de sel sont utilisées pour le hachage est stocké sur le système Y. Ces valeurs de sel sont aléatoires. Comme vous pouvez le deviner, dans le cas où le système X aurait été compromis, l’utilisation d’un sel aléatoire sur un système séparé présente un énorme avantage (scénario n ° 2). L’attaquant devra deviner des valeurs d’addition pour pouvoir craquer les hachages. Si un sel 32 bits est utilisé, 2 ^ 32 = 4 294 967 296 (environ 4,2 milliards) d'itérations peuvent être nécessaires pour chaque mot de passe deviné.
Je veux juste souligner que PHP 5.5 inclut une API de hachage de mot de passe qui fournit un wrapper autour de crypt()
. Cette API simplifie considérablement la tâche de hachage, de vérification et de redistribution des mots de passe. L’auteur a également publié un pack de compatibilité (sous la forme d’un fichier unique password.php que vous devez simplement utiliser comme variable require
), pour ceux qui utilisent PHP 5.3. 7 et plus tard et je veux utiliser ceci maintenant.
Pour le moment, il ne prend en charge que BCRYPT, mais il vise à être facilement étendu pour inclure d'autres techniques de hachage de mot de passe et, comme la technique et le coût sont stockés dans le hachage, les modifications apportées à votre technique/coût de hachage préféré n'invalideront pas les hachages actuels. utilisera automatiquement la technique/le coût correct lors de la validation. Il gère également la génération d'un sel "sécurisé" si vous ne définissez pas explicitement le vôtre.
L'API expose quatre fonctions:
password_get_info()
- renvoie des informations sur le hachage donnépassword_hash()
- crée un hachage de mot de passepassword_needs_rehash()
- vérifie si le hachage donné correspond aux options données. Utile pour vérifier si le hachage est conforme à votre schéma technique/coût actuel vous permettant de ressasser si nécessairepassword_verify()
- vérifie qu'un mot de passe correspond à un hachageAu moment où ces fonctions acceptent les constantes de mot de passe PASSWORD_BCRYPT et PASSWORD_DEFAULT, qui sont également synonymes, la différence étant que PASSWORD_DEFAULT "peut changer dans les nouvelles versions PHP lorsque des algorithmes de hachage plus récents et plus puissants sont pris en charge." L'utilisation de PASSWORD_DEFAULT et de password_needs_rehash () lors de la connexion (et de la redistribution si nécessaire) devrait vous assurer que vos hachages sont raisonnablement résistants aux attaques par force brute avec peu ou pas de travail pour vous.
EDIT: Je viens de me rendre compte que ceci est mentionné brièvement dans la réponse de Robert K. Je laisse cette réponse ici car je pense que cela fournit un peu plus d'informations sur son fonctionnement et sur la facilité d'utilisation offerte aux personnes qui ne connaissent pas la sécurité.
J'utilise Phpass , qui est une simple classe PHP pouvant être implémentée très facilement dans presque tous les projets PHP. Voir aussi The H .
Par défaut, il utilisait le cryptage disponible le plus fort implémenté dans Phpass, à savoir bcrypt
, et recourait à d'autres cryptages jusqu'à MD5 pour fournir une compatibilité ascendante à des frameworks tels que Wordpress.
Le hachage renvoyé pourrait être stocké dans la base de données tel quel. Exemple d'utilisation pour générer du hachage:
$t_hasher = new PasswordHash(8, FALSE);
$hash = $t_hasher->HashPassword($password);
Pour vérifier le mot de passe, on peut utiliser:
$t_hasher = new PasswordHash(8, FALSE);
$check = $t_hasher->CheckPassword($password, $hash);
choses à retenir
Le cryptage des mots de passe pour PHP a fait couler beaucoup d'encre, ce qui est généralement un très bon conseil. Cependant, avant même de commencer le processus d'utilisation de PHP, assurez-vous que les éléments suivants sont implémentés ou prêts à être implémentés .
SERVEUR
PORTS
Peu importe la qualité de votre cryptage, si vous ne sécurisez pas correctement le serveur qui exécute PHP et la base de données, tous vos efforts sont vains. La plupart des serveurs fonctionnent relativement de la même manière, ils ont des ports attribués pour vous permettre d'y accéder à distance via ftp ou Shell. Assurez-vous de changer le port par défaut de la connexion distante active. En ne le faisant pas, vous avez en fait obligé l'attaquant à effectuer une étape de moins pour accéder à votre système.
NOM D'UTILISATEUR
Pour tout ce qui est bon dans le monde, n'utilisez pas le nom d'utilisateur admin, root ou quelque chose de similaire. De plus, si vous êtes sur un système basé sur Unix, NE rendez PAS la connexion au compte root accessible, il devrait toujours s'agir uniquement de Sudo.
MOT DE PASSE
Vous dites à vos utilisateurs de faire de bons mots de passe pour éviter de se faire pirater, faites de même. Quel est l’intérêt de passer à travers tous les efforts pour verrouiller votre porte lorsque la porte arrière est grande ouverte.
BASE DE DONNÉES
SERVEUR
Idéalement, vous voulez que votre base de données et votre application soient sur des serveurs distincts. Ce n'est pas toujours possible en raison des coûts, mais cela permet une certaine sécurité, car l'attaquant devra suivre deux étapes pour accéder pleinement au système.
UTILISATEUR
Ayez toujours votre application avec son propre compte pour accéder à la base de données et ne lui donnez que les privilèges dont elle aura besoin.
Ensuite, ayez un compte utilisateur distinct pour vous, qui n'est pas stocké nulle part sur le serveur, pas même dans l'application.
Comme toujours, ne faites pas cette racine ou quelque chose de similaire.
MOT DE PASSE
Suivez les mêmes directives que pour tous les bons mots de passe. De même, ne réutilisez pas le même mot de passe sur les comptes SERVER ou DB du même système.
PHP
MOT DE PASSE
NE JAMAIS JAMAIS stocker un mot de passe dans votre base de données, mais stocker plutôt le hachage et le sel unique, je vais expliquer pourquoi plus tard.
HACHAGE
ONE WAY HASHING !!!!!!!, ne hachez jamais un mot de passe de manière à ce qu'il puisse être inversé, les hachages doivent être à sens unique, ce qui signifie que vous ne les inversez pas et que vous ne les comparez pas au mot de passe; vous hachissez plutôt le mot de passe entré de la même manière et comparez les deux hachages. Cela signifie que même si un attaquant a accès à la base de données, il ne sait pas quel est le mot de passe, mais uniquement le hachage qui en résulte. Ce qui signifie plus de sécurité pour vos utilisateurs dans le pire scénario possible.
Il y a beaucoup de bonnes fonctions de hachage (password_hash
, hash
, etc ...) mais vous devez sélectionner un bon algorithme pour que le hachage soit efficace. (bcrypt et ceux qui lui ressemblent sont des algorithmes décents.)
Lorsque la vitesse de hachage est la clé, plus lent est le plus résistant aux attaques Brute Force.
Une des erreurs les plus courantes dans le hachage est que les hachages ne sont pas uniques aux utilisateurs. Ceci est principalement dû au fait que les sels ne sont pas générés de manière unique.
SALAGE
Les mots de passe doivent toujours être salés avant d'être hachés. Salting ajoute une chaîne aléatoire au mot de passe, de sorte que les mots de passe similaires n'apparaissent pas de la même manière dans la base de données. Cependant, si le sel n’est pas propre à chaque utilisateur (c’est-à-dire que vous utilisez un sel codé en dur), vous n’avez pratiquement pas rendu votre sel inutile. Parce qu'une fois qu'un attaquant a trouvé un mot de passe sel, il a le sel pour tous.
Lorsque vous créez un sel, assurez-vous que le mot de passe associé au mot de passe est unique, puis stockez le hachage et le sel dans votre base de données. Cela fera en sorte qu'un attaquant devra craquer individuellement chaque sel et chaque hasch avant de pouvoir y accéder. Cela signifie beaucoup plus de travail et de temps pour l'attaquant.
UTILISATEURS CRÉANT DES MOTS DE PASSE
Si l'utilisateur crée un mot de passe via l'interface frontale, cela signifie qu'il doit être envoyé au serveur. Cela pose un problème de sécurité, car cela signifie que le mot de passe non chiffré est envoyé au serveur. Si un attaquant peut écouter et accéder, toute votre sécurité dans PHP ne vaut rien. TOUJOURS transmettre les données SÉCURISÉMENT, cela se fait via SSL, mais soyez las même si SSL n'est pas sans faille (la faille Heartbleed d'OpenSSL en est un exemple).
Demandez également à l’utilisateur de créer un mot de passe sécurisé. C’est simple et il faut toujours le faire, l’utilisateur lui en sera reconnaissant.
Enfin, quelles que soient les mesures de sécurité prises, rien n’est sécurisé à 100%. Plus la technologie à protéger évolue, plus les attaques se développent. Cependant, le fait de suivre ces étapes rendra votre site plus sûr et moins souhaitable pour les attaquants.
Voici une classe PHP qui crée facilement un hachage et un sel pour un mot de passe
Google indique que SHA256 est disponible pour PHP.
Vous devriez certainement utiliser un sel. Je vous recommande d'utiliser des octets aléatoires (et non de vous limiter aux caractères et aux nombres). Comme d'habitude, plus vous choisissez de temps, plus vous êtes sûr et lent. 64 octets devraient être bons, je suppose.
J'ai trouvé le sujet parfait sur ce sujet ici: https://crackstation.net/hashing-security.htm , je voulais que vous en tiriez parti, voici le code source qui prévient aussi du temps attaque basée aussi.
<?php
/*
* Password hashing with PBKDF2.
* Author: havoc AT defuse.ca
* www: https://defuse.ca/php-pbkdf2.htm
*/
// These constants may be changed without breaking existing hashes.
define("PBKDF2_HASH_ALGORITHM", "sha256");
define("PBKDF2_ITERATIONS", 1000);
define("PBKDF2_SALT_BYTES", 24);
define("PBKDF2_HASH_BYTES", 24);
define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);
function create_hash($password)
{
// format: algorithm:iterations:salt:hash
$salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTES, MCRYPT_DEV_URANDOM));
return PBKDF2_HASH_ALGORITHM . ":" . PBKDF2_ITERATIONS . ":" . $salt . ":" .
base64_encode(pbkdf2(
PBKDF2_HASH_ALGORITHM,
$password,
$salt,
PBKDF2_ITERATIONS,
PBKDF2_HASH_BYTES,
true
));
}
function validate_password($password, $good_hash)
{
$params = explode(":", $good_hash);
if(count($params) < HASH_SECTIONS)
return false;
$pbkdf2 = base64_decode($params[HASH_PBKDF2_INDEX]);
return slow_equals(
$pbkdf2,
pbkdf2(
$params[HASH_ALGORITHM_INDEX],
$password,
$params[HASH_SALT_INDEX],
(int)$params[HASH_ITERATION_INDEX],
strlen($pbkdf2),
true
)
);
}
// Compares two strings $a and $b in length-constant time.
function slow_equals($a, $b)
{
$diff = strlen($a) ^ strlen($b);
for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
{
$diff |= ord($a[$i]) ^ ord($b[$i]);
}
return $diff === 0;
}
/*
* PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
* $algorithm - The hash algorithm to use. Recommended: SHA256
* $password - The password.
* $salt - A salt that is unique to the password.
* $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
* $key_length - The length of the derived key in bytes.
* $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
* Returns: A $key_length-byte key derived from the password and salt.
*
* Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
*
* This implementation of PBKDF2 was originally created by https://defuse.ca
* With improvements by http://www.variations-of-shadow.com
*/
function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
$algorithm = strtolower($algorithm);
if(!in_array($algorithm, hash_algos(), true))
die('PBKDF2 ERROR: Invalid hash algorithm.');
if($count <= 0 || $key_length <= 0)
die('PBKDF2 ERROR: Invalid parameters.');
$hash_length = strlen(hash($algorithm, "", true));
$block_count = ceil($key_length / $hash_length);
$output = "";
for($i = 1; $i <= $block_count; $i++) {
// $i encoded as 4 bytes, big endian.
$last = $salt . pack("N", $i);
// first iteration
$last = $xorsum = hash_hmac($algorithm, $last, $password, true);
// perform the other $count - 1 iterations
for ($j = 1; $j < $count; $j++) {
$xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
}
$output .= $xorsum;
}
if($raw_output)
return substr($output, 0, $key_length);
else
return bin2hex(substr($output, 0, $key_length));
}
?>
En fin de compte, mathématiquement, le double hachage ne procure aucun avantage. En pratique, cependant, il est utile pour prévenir les attaques basées sur la table Rainbow. En d’autres termes, cela n’est pas plus avantageux que le hachage avec un salt, qui prend beaucoup moins de temps de traitement de votre application ou de votre serveur.
J'utilise habituellement SHA1 et salt avec l'ID utilisateur (ou une autre information spécifique à l'utilisateur), et parfois j'utilise aussi un sel constant (donc j'ai 2 parties dans le sel).
SHA1 est maintenant également considéré comme quelque peu compromis, mais dans une bien moindre mesure que MD5. En utilisant un sel (n'importe quel sel), vous empêchez l'utilisation d'un générique table Rainbow pour attaquer vos hachages (certaines personnes ont même réussi à utiliser Google comme une sorte de table Rainbow en recherchant le hacher). Un attaquant pourrait générer une table Rainbow en utilisant votre sel. C'est pourquoi vous devriez inclure un sel spécifique à l'utilisateur. De cette façon, ils devront générer une table Rainbow pour chaque enregistrement de votre système, et pas seulement un pour tout votre système! Avec ce type de salage, même le MD5 est bien sécurisé.
SHA1 et un sel devraient suffire (selon que vous codiez quelque chose pour Fort Knox ou un système de connexion pour votre liste d'achats) dans un avenir prévisible. Si SHA1 ne vous convient pas, utilisez SHA256 .
L'idée d'un sel est de déséquilibrer les résultats de hachage, pour ainsi dire. Il est connu, par exemple, que le hachage MD5 d'une chaîne vide est d41d8cd98f00b204e9800998ecf8427e
. Donc, si quelqu'un avec assez de mémoire verrait ce hachage et saurait que c'est le hachage d'une chaîne vide. Mais si la chaîne est salée (par exemple, avec la chaîne "MY_PERSONAL_SALT
"), le hachage de la "chaîne vide" (c'est-à-dire "MY_PERSONAL_SALT
") devient aeac2612626724592271634fb14d3ea6
, et n'est donc pas évident. revenir en arrière. Ce que j'essaie de dire, c'est qu'il vaut mieux utiliser n'importe quel sel , que de ne pas le faire. Par conséquent, il n’est pas très important de savoir quel sel utiliser.
Il existe en fait des sites Web qui ne font que cela - vous pouvez le nourrir avec un hachage (md5) et créer un texte en clair connu qui génère ce hachage particulier. Si vous pouviez accéder à une base de données qui stocke des hachages md5 simples, il serait facile de saisir le hachage de l'administrateur pour un tel service et de vous connecter. Cependant, si les mots de passe étaient salés, un tel service deviendrait inefficace.
De plus, le double hachage est généralement considéré comme une mauvaise méthode, car il diminue l'espace de résultat. Tous les hachages populaires sont de longueur fixe. Ainsi, vous ne pouvez avoir qu'une valeur finie de cette longueur fixe et les résultats deviennent moins variés. Ceci pourrait être considéré comme une autre forme de salage, mais je ne le recommanderais pas.