web-dev-qa-db-fra.com

Le hashCode () de Java est-il sécurisé?

Sur nos vues dans une application Web Java Java, j'utilise actuellement hashCode comme identifiant pour les objets afin qu'à la fin du serveur je puisse récupérer le même objet.

Cependant, je me demande à quel point le hashCode de Java est vraiment sécurisé pour que quelqu'un ne puisse pas le pirater pour récupérer les objets d'une autre personne. Je ne suis pas très enclin au mécanisme de cryptage-décryptage car il provoque beaucoup de CPU.

Quels autres mécanismes rapides encore sécurisés puis-je utiliser?

21
Novice User

Vous brisez l'un des tabous hashCode(); vous utilisez sa sortie comme identifiant de clé. C'est faux.

Vous voyez, la sortie de hashCode() (dans son implémentation par défaut) est un entier non signé 32 bits, soit environ 4 milliards de hashCodes uniques. Sonne beaucoup? Enfin, pas tant que ça. L'application du problème d'anniversaire dans ce cas montre que, avec environ 77000 objets, vous avez environ 50% de chances de collision. 50% de chances que deux objets aient le même hashCode.

Un autre problème est que l'implémentation de hashCode() peut changer d'une version Java version à l'autre. Elle n'est pas destinée à être l'identifiant permanent d'un objet, donc rien ne l'oblige à être cohérent entre les versions.

Si vous insistez pour utiliser des hachages comme identificateurs d'objet, il est préférable d'avoir votre propre méthode au lieu de hashCode() à utiliser pour vos identificateurs de clé (par exemple, getMySpecialHashKey(). Vous pouvez utiliser quelque chose comme MessageDigest.getInstance("SHA-256") pour digérer l'objet dans une jolie clé 256 bits.

Ma recommandation: Abandonnez l'idée de hacher l'objet et générez plutôt un identifiant aléatoire pour votre objet lorsque vous le construisez. Quelque chose dans le sens de (en Java)

SecureRandom secRand = new SecureRandom();
byte[] objIdBytes = new byte[16]; //128-bit
secRand.nextBytes(objIdBytes);
String objId = Base64.encodeBase64String(objIdBytes); //Here's your ID

Vous semblez également lier l'accès à un objet uniquement à la connaissance de sa clé. C'est également faux. Un modèle basé sur les autorisations approprié avec une authentification et une autorisation appropriées est nécessaire.

54
Adi

Java hashCode() n'a jamais été conçu pour être utilisé comme ça. Ne le fais jamais! Il est même légal (bien que non recommandé) que toutes les instances d'une classe retournent le même hashCode. Le contrat en Java est "deux objets qui sont considérés comme égaux doivent avoir le même hashcode". Ni plus, ni moins. Il serait par exemple valide de renvoyer le hashcode 1 pour tous les nombres irréguliers et 0 pour tous même ceux-là.

hashCode est utilisé pour une recherche plus rapide dans des collections telles que HashMap et les collisions sont attendues.

De nombreuses classes définissent leur propre version de hashCode(), et si vous connaissez le code, vous pouvez souvent facilement deviner ou deviner le hashcode.

Donc, ce n'est absolument pas sûr.

30
Axel

Il n'est pas cryptographiquement sécurisé, car cela ne fait pas partie de ses exigences.

La façon dont le hashCode est implémenté est un détail d'implémentation jusqu'à la JVM et peut être différent pour différents types d'objet (les objets peuvent remplacer la méthode hashCode et fournir une implémentation propre).

Le but du Java hashCode est d'identifier les objets lors de leur placement dans des tables de hachage. Sa principale exigence est la performance. Il a également une longueur de seulement 32 bits, ce qui est trop court pour éviter les collisions. Pour sa destination (tables de hachage) deux objets ayant le même hachage n'est qu'un problème mineur, mais identifier les objets sans ambiguïté est un gros problème.

Mais vous ne devez généralement autoriser aucun utilisateur à accéder à un objet simplement parce qu'il connaît le code de hachage des objets. Utilisez un système de gestion des droits approprié. Utilisez des comptes d'utilisateurs protégés par mot de passe où chaque utilisateur dispose d'un ensemble différent de paramètres d'autorisation. Lorsque l'utilisateur essaie d'accéder à un objet, vérifiez si ses autorisations lui permettent de le faire et rejetez la demande dans le cas contraire.

12
Philipp

Ce n'est certainement pas suffisamment sécurisé pour une situation où la supposition de valeurs peut révéler des informations.

Au moins certains des remplacements ne sont même pas suffisamment sécurisés pour être utilisés comme code de hachage face à une entrée arbitraire sélectionnée par l'utilisateur (il est vraiment facile de faire une attaque de hachage-DoS contre quoi que ce soit en utilisant String.hashCode() de Java passer outre).

Dans les cas où vous voulez un identifiant, je recommande de prendre un identifiant simple (par exemple une clé numérique dans une base de données, un entier incrémenté atomiquement qui est une clé dans une table de hachage, etc.), puis d'ajouter un hachage cryptographique de cela et un sel .

Autrement dit, votre ID divulgué publiquement serait de la forme (sous une forme indépendante de la langue):

Concatenate(PrivateID, HexString(SHA256(UTF8Bytes(Concatenate(Salt, PrivateID)))))

(Vous pouvez supprimer une partie du hachage pour un identifiant plus petit au prix d'un temps réduit à la force brute).

Ensuite, l'ID privé peut être obtenu en tant que sous-chaîne, et l'ID complet peut être vérifié à nouveau. La procédure générale est également facilement transposable entre les langues.

La poignée de cycles de CPU que cela coûtera n'aura pas un grand impact par rapport au reste du système, à moins que votre système ne soit si trivial que vous n'utiliserez pas beaucoup de CPU de toute façon, donc à moins que vous ne l'exécutiez quelque chose de vraiment faible puissance (comme, beaucoup moins puissant qu'un téléphone bon marché), ce ne sera pas un problème.

Dans les cas où vous souhaitez réellement utiliser un code de hachage en tant que code de hachage et devez gérer une entrée sélectionnée par l'utilisateur, utilisez un algorithme de hachage pouvant être semé (par exemple SpookyHash) et basez votre graine sur le temps de démarrage (ou mieux encore , un mélange de temps de démarrage et de temps de création du conteneur de hachage). (Rien à voir avec les hachages cryptographiques, ils peuvent donc être beaucoup plus rapides; le niquement risque de sécurité que cela évite est le hachage-DoSing).

2
Jon Hanna