Point 85: Préférez les alternatives à la sérialisation Java

85. Pensez à d'autres moyens que la sérialisation en Java

La sérialisation est vulnérable

Le problème fondamental de la sérialisation est que les zones qui peuvent être attaquées sont trop grandes et se propagent constamment. Le graphe d'objets (une image d'un groupe d'objets connectés par référence) est restauré par la méthode readObject d'ObjectInputStream. Cette méthode vous permet d'instancier des objets de presque n'importe quel type sur le chemin de classe tant que le type implémente Serializable. Dans le processus de désérialisation d'un flux d'octets, cette méthode peut exécuter n'importe quel type de code qui se trouve sur le chemin de classe et implémente Serialize. Par conséquent, tous ces types sont ciblés pour les attaques.

Gadget, chaîne de gadgets

Même si vous supprimez la vulnérabilité d'une classe sérialisable qui peut être attaquée, l'application elle-même peut toujours être vulnérable. Si vous créez une chaîne de gadgets en combinant des méthodes qui peuvent effectuer des traitements dangereux (appelés gadgets) à partir de méthodes de type sérialisable, il arrive parfois que du code natif arbitraire puisse être exécuté. En fait, en 2016, un piratage a été commis contre la San Francisco Metropolitan Transit Agency Municipal Railway en utilisant ce mécanisme.

Bombe de désérialisation

Comme mentionné ci-dessus, vous pouvez facilement créer un flux qui prend beaucoup de temps à désérialiser sans utiliser de gadget, et vous pouvez faire une attaque DoS avec cela. Ces flux sont appelés bombes de désérialisation.

// Deserialization bomb - deserializing this stream takes forever
static byte[] bomb() {
    Set<Object> root = new HashSet<>();
    Set<Object> s1 = root;
    Set<Object> s2 = new HashSet<>();
    for (int i = 0; i < 100; i++) {
        Set<Object> t1 = new HashSet<>();
        Set<Object> t2 = new HashSet<>();
        t1.add("foo"); // Make t1 unequal to t2
        s1.add(t1);  s1.add(t2);
        s2.add(t1);  s2.add(t2);
        s1 = t1;
        s2 = t2;
    }
    return serialize(root); // Method omitted for brevity
}

Dans le code ci-dessus, un HashSet a 100 couches d'éléments HashSet. Lorsque vous créez une instance HashSet, vous devez calculer le hashcode pour chaque élément. Par conséquent, il est nécessaire d'appeler hashCode 2 à la 100e puissance et le traitement n'est pas du tout terminé.

Que devrais-je faire?

Comment gérer les attaques ci-dessus liées à la sérialisation?

Utiliser d'autres mécanismes

** Le meilleur moyen est de ne pas désérialiser. ** ** ** Il n'y a aucune raison d'utiliser la sérialisation Java dans les nouveaux systèmes. ** ** Il existe de meilleurs mécanismes pour traduire les séquences d'octets et les objets, appelés représentations de données structurées multiplateformes.

JSON et Protobuf

Les représentations typiques de données structurées multiplateformes sont JSON et Protobuf. La différence la plus importante entre JSON et Protobuf est que JSON est basé sur du texte et lisible par l'homme, tandis que Protobuf est plus efficace en binaire.

Ne désérialisez pas les données non fiables

Pour la maintenance et le développement de systèmes hérités, la sérialisation en Java peut être inévitable. Dans de tels cas, vous devez prendre des mesures telles que ** ne pas désérialiser les données non fiables **. En particulier, n'acceptez pas le trafic RMI provenant de sources non fiables.

Utiliser la fonction de filtrage au moment de la désérialisation

Si la sérialisation en Java est inévitable et que la sécurité des données à désérialiser est douteuse, java.io.ObjectInputFilter (introduit à partir de Java9 et rétroporté vers 6,7,8) est un filtre de désérialisation d'objet. ) Devrait être utilisé. Cela offre la possibilité de filtrer les flux avant qu'ils ne soient désérialisés. Il est décidé de rejeter ou d'accepter classe par classe. À ce stade, vous pouvez sélectionner le format de liste blanche ou le format de liste noire, mais comme la liste noire ne peut protéger que des menaces connues, la liste blanche doit être adoptée. La fonction de filtrage empêche également une utilisation excessive de la mémoire et des graphes d'objets trop profonds, mais elle n'empêche pas les bombes de désérialisation mentionnées ci-dessus.

Recommended Posts

Point 85: Préférez les alternatives à la sérialisation Java
Élément 28: Préférer les listes aux tableaux
Rubrique 65: Préférez les interfaces à la réflexion
Rubrique 43: Préférez les références de méthode aux lambdas
Sérialisation Java
Point 42: Préférez les lambdas aux classes anonymes
Élément 39: Préférez les annotations aux modèles de dénomination
Point 58: Préférez les boucles for-each aux boucles for traditionnelles
Élément 23: Préférez les hiérarchies de classes aux classes balisées
Point 61: Préférez les types primitifs aux primitives encadrées
[Java] Introduction à Java
Notes de sérialisation Java
Introduction à Java
Élément 81: Préférez les utilitaires de concurrence pour attendre et notifier
Élément 80: Préférez les exécuteurs, les tâches et les flux aux threads
Élément 89: Pour le contrôle d'instance, préférez les types enum à readResolve
Changements de Java 8 à Java 11
Somme de Java_1 à 100
[Java] Connectez-vous à MySQL
Efficacité de Java 3rd Edition Section 85 Choix d'une alternative à la sérialisation Java
Améliorations de Kotlin à Java
Java - Sérialisation et désérialisation
De Java à Ruby !!
Introduction à la commande java
Sérialisation d'objets Java pourquoi et quand
Comment abaisser la version java
Migration de Cobol vers JAVA
[Java] Comment utiliser Map
Java ajoute un tableau au PDF
Comment désinstaller Java 8 (Mac)
Java pour jouer avec Function
Java - Comment créer JTable
Comment utiliser java Facultatif
Nouvelles fonctionnalités de Java7 à Java8
Comment réduire les images Java
Comment rédiger un commentaire java
Connectez-vous de Java à PostgreSQL
[Java] Comment utiliser removeAll ()
[Java] Introduction à l'expression lambda
Shell pour tuer les processus Java
Comment utiliser Java Map
Comment définir des constantes Java
Connectez-vous à DB avec Java
Connectez-vous à MySQL 8 avec Java
[java] Raisons d'utiliser statique
Comment utiliser les variables Java
Sérialisation / désérialisation Json dans Java 1.4
[Java] Introduction à l'API Stream
Java8 pour démarrer maintenant ~ Facultatif ~
Comment convertir la base Java
[Java] Convertir ArrayList en tableau
Thread Java pour comprendre vaguement
[Java] Comment implémenter le multithreading
De Java inefficace à Java efficace
Comment initialiser un tableau Java
[Introduction aux jeux Janken (comme)] Java