Punkt 85: Bevorzugen Sie Alternativen zur Java-Serialisierung

85. Überlegen Sie sich andere Möglichkeiten als die Serialisierung in Java

Die Serialisierung ist anfällig

Das grundlegende Problem bei der Serialisierung besteht darin, dass die Bereiche, die angegriffen werden können, zu groß sind und sich ständig ausbreiten. Das Objektdiagramm (ein Bild einer Gruppe von Objekten, die durch Referenz verbunden sind) wird durch die readObject-Methode von ObjectInputStream wiederhergestellt. Mit dieser Methode können Sie Objekte fast aller Art im Klassenpfad instanziieren, solange der Typ Serializable implementiert. Beim Deserialisieren eines Byte-Streams kann diese Methode jeden Codetyp ausführen, der sich im Klassenpfad befindet, und Serialize implementieren. Daher sind alle diese Typen für Angriffe vorgesehen.

Gadget, Gadget-Kette

Selbst wenn Sie die Sicherheitsanfälligkeit aus einer serialisierbaren Klasse entfernen, die angegriffen werden kann, ist die Anwendung selbst möglicherweise weiterhin anfällig. Wenn Sie eine Gadget-Kette erstellen, indem Sie Methoden kombinieren, die eine gefährliche Verarbeitung (sogenannte Gadgets) aus serialisierbaren Methoden ausführen können, kann manchmal beliebiger nativer Code ausgeführt werden. Tatsächlich wurde 2016 mit diesem Mechanismus ein Hack gegen die Stadtbahn der San Francisco Metropolitan Transit Agency durchgeführt.

Deserialisierungsbombe

Wie oben erwähnt, können Sie problemlos einen Stream erstellen, dessen Deserialisierung viel Zeit in Anspruch nimmt, ohne ein Gadget zu verwenden, und Sie können damit einen DoS-Angriff ausführen. Solche Ströme werden Deserialisierungsbomben genannt.

// 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
}

Im obigen Code verfügt ein HashSet über 100 Schichten von HashSet-Elementen. Wenn Sie eine HashSet-Instanz erstellen, müssen Sie den Hashcode für jedes Element berechnen. Daher ist es notwendig, Hashcode 2 zur 100. Potenz aufzurufen, und die Verarbeitung ist überhaupt nicht abgeschlossen.

Was soll ich machen?

Wie sollen wir mit den oben genannten Angriffen im Zusammenhang mit der Serialisierung umgehen?

Verwenden Sie andere Mechanismen

** Der beste Weg ist, nicht zu deserialisieren. ** ** ** ** Es gibt keinen Grund, die Java-Serialisierung in neuen Systemen zu verwenden. ** ** ** Es gibt bessere Mechanismen zum Übersetzen von Bytesequenzen und Objekten, die als plattformübergreifende Darstellungen strukturierter Daten bezeichnet werden.

JSON und Protobuf

Typische plattformübergreifende Darstellungen strukturierter Daten sind JSON und Protobuf. Der wichtigste Unterschied zwischen JSON und Protobuf besteht darin, dass JSON textbasiert und für Menschen lesbar ist, während Protobuf binär effizienter ist.

Deserialisieren Sie keine unzuverlässigen Daten

Die Serialisierung in Java kann bei der Wartung und Entwicklung von Legacy-Systemen unvermeidbar sein. In solchen Fällen sollten Sie Maßnahmen ergreifen wie ** unzuverlässige Daten nicht deserialisieren **. Akzeptieren Sie insbesondere keinen RMI-Verkehr aus nicht vertrauenswürdigen Quellen.

Verwenden Sie die Filterfunktion zum Zeitpunkt der Deserialisierung

Wenn eine Serialisierung in Java unvermeidbar ist und die Sicherheit der zu deserialisierenden Daten zweifelhaft ist, ist java.io.ObjectInputFilter (von Java9 eingeführt und auf 6,7,8 zurückportiert) ein Objektdeserialisierungsfilter. ) Sollte benutzt werden. Dies bietet die Möglichkeit, Streams zu filtern, bevor sie deserialisiert werden. Es wird entschieden, ob Klasse für Klasse abgelehnt oder akzeptiert wird. Zu diesem Zeitpunkt können Sie das Whitelist-Format oder das Blacklist-Format auswählen. Da die Blacklist jedoch nur vor bekannten Bedrohungen schützen kann, sollte die Whitelist übernommen werden. Die Filterfunktion verhindert auch eine übermäßige Speichernutzung und übermäßig tiefe Objektgraphen, verhindert jedoch nicht die oben erwähnten Deserialisierungsbomben.

Recommended Posts

Punkt 85: Bevorzugen Sie Alternativen zur Java-Serialisierung
Punkt 28: Listen Arrays vorziehen
Punkt 65: Schnittstellen der Reflexion vorziehen
Punkt 43: Bevorzugen Sie Methodenverweise auf Lambdas
Java-Serialisierung
Punkt 42: Bevorzugen Sie Lambdas gegenüber anonymen Klassen
Punkt 39: Bevorzugen Sie Anmerkungen gegenüber Namensmustern
Punkt 58: Bevorzugen Sie für jede Schleife herkömmliche Schleifen
Punkt 23: Bevorzugen Sie Klassenhierarchien gegenüber markierten Klassen
Punkt 61: Bevorzugen Sie primitive Typen gegenüber primitiven Boxen
[Java] Einführung in Java
Hinweise zur Java-Serialisierung
Einführung in Java
Punkt 81: Bevorzugen Sie Parallelitätsdienstprogramme, um zu warten und zu benachrichtigen
Punkt 80: Ziehen Sie Executoren, Aufgaben und Streams Threads vor
Punkt 89: Für die Steuerung bevorzugen Sie Aufzählungstypen gegenüber readResolve
Änderungen von Java 8 zu Java 11
Summe von Java_1 bis 100
[Java] Stellen Sie eine Verbindung zu MySQL her
Effektive Java 3rd Edition Abschnitt 85 Auswählen einer Alternative zur Java-Serialisierung
Kotlins Verbesserungen an Java
Java - Serialisierung und Deserialisierung
Von Java zu Ruby !!
Einführung in den Java-Befehl
Java Object Serialization warum und wann
So senken Sie die Java-Version
Migration von Cobol nach JAVA
[Java] Verwendung von Map
Java fügt PDF eine Tabelle hinzu
So deinstallieren Sie Java 8 (Mac)
Java zum Spielen mit Function
Java - So erstellen Sie JTable
Verwendung von Java Optional
Neue Funktionen von Java7 bis Java8
So minimieren Sie Java-Images
Wie schreibe ich einen Java-Kommentar
Stellen Sie eine Verbindung von Java zu PostgreSQL her
[Java] Verwendung von removeAll ()
[Java] Einführung in den Lambda-Ausdruck
Shell zum Beenden von Java-Prozessen
Verwendung von Java Map
So legen Sie Java-Konstanten fest
Stellen Sie mit Java eine Verbindung zur Datenbank her
Stellen Sie mit Java eine Verbindung zu MySQL 8 her
[Java] Gründe für die Verwendung von statischen
Verwendung von Java-Variablen
Json-Serialisierung / Deserialisierung in Java 1.4
[Java] Einführung in die Stream-API
Java8 startet jetzt ~ Optional ~
So konvertieren Sie Java Base
[Java] Konvertiert ArrayList in Array
Java-Thread locker zu verstehen
[Java] So implementieren Sie Multithreading
Von ineffektivem Java zu effektivem Java
So initialisieren Sie ein Java-Array
[Einführung in Janken (ähnliche) Spiele] Java