8
votes

Puis-je utiliser l'objet # HashCode pour stocker le hachage d'un mot de passe?

Pour enregistrer un fichier I défini la méthode suivante

public String encrypt(String password) {
        String hash = "";
        try {
            MessageDigest md5 = MessageDigest.getInstance("SHA-512");
            byte [] digest = md5.digest(password.getBytes("UTF-8"));
            hash = Arrays.toString(digest);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return hash;
    }


2 commentaires

Pour la question mise à jour, non. MD5 est considéré comme cassé. Utilisez un algorithme de la famille SHA-2. En fait, NIST encourage les agences fédérales à utiliser SHA-2 et n'a recommandé d'utiliser SHA-1 depuis 2010. Il existe certaines attaques connues contre SHA-1. Ref: CSRC.NIST.GOV/GROUPS/STRO/TOOLKIT/SECURE_HASHING.HTML < / a>


Inconnu: Il y a une dernière chose qu'aucun d'entre nous ne pensait à mentionner: les mots de passe ne doivent pas être détruits directement, vous devriez ajouter un sel . Voir ma réponse mise à jour.


8 Réponses :


2
votes

Honnêtement, je ne sais pas comment la collision résistant à Java's hashcode () est. Si je devais deviner, je dirais pas très. Je l'ai testé avant et j'ai trouvé quelques collisions après quelques centaines de milliers d'intrants.

Puisque vous avez affaire à des mots de passe ici, vous devriez vraiment utiliser un hasch cryptographique comme SHA1.


1 commentaires

Je jouais dans l'autre nuit avec des permutations et j'ai trouvé des collisions de hashcode () en 9! Entrées.




1
votes

Je craquerais que ce code soit non portable. Il n'y a aucune garantie qu'un JVM produira la même valeur de hachage qu'une autre JVM. Cela semble très risqué.


2 commentaires

L'algorithme de hachage est spécifié. it est portable sur JVMS.


Ah, oui, j'ai oublié une version spéciale définie pour les chaînes. Bonne prise.



5
votes

string.hashcode ne convient pas aux mots de passe de hachage. Vous avez besoin d'un hachage cryptographique à la place.

string.hashcode est conçu pour être très rapide pour calculer. Son utilisation principale est pour une clé dans une table de hachage. Pour cette utilisation, une collision occasionnelle n'est pas un problème. Les hachages cryptographiques sont plus lentes à calculer, mais par définition, personne ne sait générer des collisions pour une bonne cryptographie.

Plus important encore, étant donné la valeur du mot de passe.hashscode () , il est possible de trouver mot de passe (avec une grande confiance, mais pas avec certitude car de nombreux mots de passe ont la même chose hacher). Ce n'est pas quelque chose que vous voulez jamais arriver. Les hachages cryptographiques, d'autre part, sont conçues de sorte qu'il est impossible de trouver le mot de passe connaissant le hachage (parlant mathématiquement, personne ne sait trouver le mot de passe du hachage de leur vie).

Les hachages cryptographiques sont disponibles dans la bibliothèque standard Java, via java.security.messagedigest .

ajouté : il y a une complication supplémentaire: c'est une mauvaise idée de passer directement un hasch d'un mot de passe. La raison en est qu'un attaquant pourrait essayer tous les mots de passe probables (par exemple des mots dictionnaires, les noms des personnes, etc.) La solution standard à ce problème est de concaténer le mot de passe avec une chaîne aléatoire appelée "http://fr.wikipedia.org/wiki/salt_%28Cryptography%29" rel = "Nofollow NOREFERRER"> sel avant de calculer le hachage: vous faites quelque chose comme sha.digest ((sel + mot de passe) .getbytes ()) . Le sel le rend agréable à l'attaquant de précalcomputer tous les hachages de mots de passe probables.

Généralement généré de manière aléatoire lorsque l'utilisateur choisit son mot de passe, et il est stocké à côté du hachage de mot de passe dans une base de données utilisateur, mais à partir de ce que vous montrez de votre schéma, il n'y a rien de tel. Compte tenu de votre conception, il serait raisonnable d'utiliser le nom de fichier comme sel: FileName.concat (chiffrement (nom de fichier + mot de passe)) . .


3 commentaires

Vous ne pouviez pas trouver le mot de passe de certains (après tout, il y aura de nombreuses chaînes de hachage à la même valeur) - mais vous pouvez trouver une chaîne qui donne le même hachage.


@Jon: Si vous supposez que le mot de passe est composé de caractères imprimables et a une longueur dans une plage étroite, il y a une bonne chance que vous puissiez le trouver. Et c'est le vrai prix, car les utilisateurs réutilisent leurs mots de passe.


Oui, il y a une chance raisonnable. C'est beaucoup mieux avec votre édition :)



17
votes

C'est une mauvaise idée - vous devez utiliser un hachage cryptographique normal tel que SHA-1, comme indique NullUSeException.

Cependant, il serait portable - le docs pour string.hashcode () Indiquez explicitement l'algorithme. Tout JRE mettant en œuvre les documents correctement doit donner le même code de hachage. Cependant, en raison de la façon dont les œuvres d'algorithme Hashcode () , il est assez facile de trouver une chaîne qui générera un code de hash particulier - même un commençant par un préfixe spécifique - donc un attaquant qui connaissait la Le hash pourrait attaquer votre application très facilement. Les hachages cryptographiques sont conçues pour rendre difficile l'ingénieur une clé pour correspondre à un hachage particulier.


0 commentaires

1
votes

Voici la mise en œuvre String.HashCode ():

s [0] * 31 ^ (N-1) + S [1] * 31 ^ (N-2) + ... + S [N-1]

disponible publiquement ici ...

Ceci est en réalité VM-Indépendant, et il n'a pas été dépendant de la version Java dans le passé. La mise en œuvre est restée la même.

La sécurité de collision est ok IMHO, mais c'est une mauvaise idée de l'utiliser à des fins cryptographiques pour des raisons évidentes.


0 commentaires

2
votes

Ce n'est pas aussi difficile que vous pourriez penser aux données de hachage, et il vaut mieux utiliser un algorithme de hachage réel. Si vous avez un tableau d'octets contenant le mot de passe, vous pouvez simplement faire quelque chose comme ça. Si vous obtenez le tableau d'octet à partir d'une chaîne, assurez-vous de spécifier le codage (c'est-à-dire UTF-8) lorsque vous appelez GetBytes ();

Voici un exemple simple utilisant MD5. P>

    try {
        MessageDigest md5 = MessageDigest.getInstance( "MD5" );

        byte [] digest = md5.digest( data );

        return digest;
    } catch( java.security.NoSuchAlgorithmException ex ) {
        // Insert error handling here.
    }


4 commentaires

Merci. Y a-t-il une possibilité que je n'ai pas à retourner un tableau d'octets?


Eh bien, vous pouvez retourner ce que vous voulez. La valeur de retour de la Digest est une matrice d'octet. Vous pouvez l'encoder hex ou base64 si vous préférez renvoyer une chaîne.


Retourne nouvelle chaîne (Digest, caractères.utf_8); (nécessite GUAVA pour les constantes de caractèrests)


Bon exemple, mais je ne recommanderais pas MD5 pour les mots de passe



0
votes

Le problème n ° 1 est le hachage n'est que 32 bits. C'est bien trop court. Un enfant avec basique peut le casser en une seconde.

MD5 est de 128 bits de long et il est considéré comme faible maintenant.


2 commentaires

MD5 n'est pas considéré comme faible en raison de sa longueur, mais parce qu'ils ont trouvé une façon de générer des collisions.


collision plausible en raison de sa longueur.