L'extrait ci-dessous est extrait d'un article qui explique la possibilité d'une attaque par déni de service (DoS) en raison de fonctions de hachage non aléatoires utilisées dans les structures de données de hachage.
[…] La condition peut être exploitée en exploitant des collisions prévisibles dans les algorithmes de hachage sous-jacents.
Afin de le vérifier, je suis allé à travers l'implémentation de référence de Java HashMap d'Oracle et j'ai en effet trouvé une fonction de hachage statique utilisée:
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
Un autre papier sur le sujet raconte:
Un serveur Tomcat 6.0.32 analyse une chaîne de 2 Mo de clés en collision en environ 44 minutes de temps processeur i7. Ainsi, un attaquant disposant d’environ 6 kbit/s peut garder un noyau i7 constamment occupé. Si l'attaquant dispose d'une connexion Gigabit, il peut occuper environ 100 000 cœurs i7.
Comment pouvons-nous nous protéger contre cette vulnérabilité? De plus, avec autant de logiciels que nous utilisons, nous utilisons le code source ouvert (Tomcat, etc.) qui repose sur cette implémentation.
Dites qu'un formulaire de commentaire sur un blog accepte les paramètres - prénom, nom, commentaire comme paramètres de publication. En interne, Tomcat stocke ces paramètres sous forme de HashMap.
La structure logique de ce HashMap est comme ça -
"first_name" --> "Sripathi"
"last_name" --> "Krishnan"
"comment" ---> "DoS using poor Hashes"
Mais la structure physique est différente. Les clés sont d'abord converties en un hashCode, puis le hashCode est converti en un index de tableau.
La structure physique idéale devient ainsi -
0 --> "Sripathi"
1 --> "Krishnan"
2 --> "DoS using poor Hashes"
Mais les clés possibles sont infinies. Donc, à un moment donné, deux clés auront le même code de hachage. Cela devient une collision de hachage.
Avec les collisions, le structure physique devient:
0 --> "Sripathi" -> "Krishnan"
1 --> Empty
2 --> "DoS using poor hashes"
Lorsque vous avez des collisions de hachage, insérer une nouvelle entrée signifie itérer sur tous les éléments séquentiellement simplement pour savoir s’il existe déjà dans la carte. L'insertion d'un élément devient O(n) complexité. L'insertion de n éléments en fait une complexité O (n * n).
En bref: si vous insérez des milliers de clés ayant le même hashCode, le serveur nécessitera beaucoup de cycles de la CPU.
En Java, "Aa" et "BB" ont le même code de hachage.
En raison d'une propriété appelée "Equivalent Substrings", nous pouvons générer plusieurs autres chaînes avec le même hashcode, en commençant par ces 2 chaînes.
Première itération: "AAAA", "AABb", "BbAA", "BbBb" ont le même code de hachage
Nous avons maintenant 4 chaînes avec le même code de hachage. Nous pouvons les permuter pour générer 16 chaînes qui auront le même code de hachage. Par exemple :
"AaAaAaAa", "AaAaBBBB", "AaAaAaBB", "AaAaBBAa",
"BBBBAaAa", "BBBBBBBB", "BBBBAaBB", "BBBBBBAa",
"AaBBAaAa", "AaBBBBBB", "AaBBAaBB", "AaBBBBAa",
"BBAaAaAa", "BBAaBBBB", "BBAaAaBB", "BBAaBBAa",
Toutes ces 16 chaînes ont le même code de hachage.
Vous pouvez maintenant prendre ces 16 chaînes et générer 256 chaînes qui ont le même hashcode.
En bref: il est très facile de générer un grand ensemble de chaînes qui auront le code de hachage exact.
S'agissant simplement d'une requête POST, un attaquant peut également utiliser des navigateurs innocents pour attaquer un serveur. Il vous suffit de rechercher un site Web présentant une vulnérabilité de script intersite, d'intégrer du code pour effectuer une demande POST, puis d'utiliser l'ingénierie sociale pour diffuser le lien au plus grand nombre d'utilisateurs possible.
En général, la plateforme sous-jacente ne peut pas résoudre ce problème. Ceci est considéré comme un problème de cadre d'application. En d'autres termes, Tomcat doit résoudre ce problème, pas Oracle/Sun.
Les solutions possibles incluent:
Limitez le nombre de paramètres POST - Tomcat 6.035+ a un nouveau paramètre maxParameterCount. La valeur par défaut est 10 000. Plus le prix est bas, mieux c'est, tant que cela ne rompt pas avec vos fonctionnalités.
Limitez la taille de la requête POST - Pour que l'attaque fonctionne, la charge utile doit être énorme. La valeur par défaut POST autorisée par Tomcat est de 2 Mo. Réduire ce chiffre à 200 Ko réduira l'efficacité de cette attaque. Le paramètre dans Tomcat est maxPostSize
Pare-feu d'application Web - Si vous avez un pare-feu d'application Web, vous pouvez le configurer pour bloquer les demandes qui paraissent suspectes. C'est une mesure réactive, mais il est agréable d'avoir au cas où vous ne pouvez pas utiliser l'une des solutions ci-dessus.
FYI - La documentation de Tomcat est ici - http://Tomcat.Apache.org/Tomcat-6.0-doc/config/http.html
La solution la plus simple consiste à effectuer une mise à niveau vers une version fixe de Tomcat. Cependant, je suppose que vous souhaitez connaître les détails de ce que les employés de Tomcat auraient besoin de changer.
Cette attaque fonctionne en exploitant un détail d'implémentation commune des structures de données de hachage - en utilisant des listes chaînées pour contenir toutes les valeurs dont le hachage est identique. L'ajout de valeurs à cette liste chaînée est inefficace car la taille de la liste devient volumineuse. Un attaquant peut créer une liste de valeurs connue pour générer des hachages en collision, forçant ce comportement inefficace. Afin de vous protéger contre cela, vous avez quelques options:
Empêcher les collisions - empêchez l'attaquant de générer des valeurs en collision en ayant un facteur (pseudo) aléatoire dans votre fonction de hachage. Perl le fait depuis longtemps.
Utilisez quelque chose en plus des listes chaînées pour vos compartiments - l'attaque fonctionne car l'insertion de N éléments dans une liste chaînée entraîne une croissance de N ^ 2. Si vous utilisez un arbre équilibré ou une autre structure ayant une croissance de N logN lors de l'insertion, le problème doit être atténué. Cela peut sacrifier certaines performances meilleures/moyennes afin de limiter la gravité du pire des cas.
Les versions de Tomcat concernées sont Apache Tomcat <= 5.5.34, <= 6.0.34, <= 7.0.22 selon le lien que vous avez fourni. La page répertorie Apache Tomcat> = 5.5.35,> = 6.0.35,> = 7.0.23 en tant que versions corrigées.
Voici un code python pour générer ces clés ... Je ne l’ai pas encore testé, mais je serais intéressé de recevoir des commentaires:
#!/usr/bin/python
import sys
alphabet = ["Aa","BB"]
def func(str, length):
global alphabet
if(length != 0):
for x in alphabet:
new_str = str+x
func(new_str, length-1)
else:
sys.stdout.write(str+"=&")
for x in range(1,16):
func("",x)
Java HashMap/HashTable peut effectuer l'opération de redimensionnement lorsque le seuil d'entrée rempli est atteint. Il est difficile de dire qu’un seau fixe HashMap vous attend. En raison de l'opération de sélection du compartiment, vous devez suivre deux étapes: la première consiste à prendre la valeur de hachage de la clé spécifiée; une autre étape principale est l'opération restante avec la taille totale du compartiment (la taille a été modifiée par 'redimensionner').