Probleme bei der JSON-Deserialisierung mit Jackson ObjectMapper in Java
1. Dezember 2021
0 Min. LesezeitIn einem früheren Blogbeitrag haben wir uns Javas benutzerdefinierte Serialisierungs-Plattform und ihre Auswirkungen auf die Sicherheit angesehen. Vor Kurzem habe ich außerdem darüber geschrieben, wie Verbesserungen in Java 17 dabei helfen können, unsichere Deserialisierung zu verhindern. Heutzutage sind viele jedoch nicht mehr so stark auf Javas benutzerdefinierte Serialisierung angewiesen und entscheiden sich stattdessen für JSON. JSON ist das am weitesten verbreitete Format für die Datenserialisierung. Es ist für Menschen lesbar und nicht an Java gebunden.
Eine der am häufigsten verwendeten Bibliotheken ist jackson-databind. Sie stellt einen ObjectMapper bereit, mit dem Sie Ihr Objekt in JSON und umgekehrt umwandeln können.
Da diese Bibliothek so beliebt ist, sollten Sie wissen, dass für die Bibliothek jackson-databind in den vergangenen Jahren zahlreiche Schwachstellen gemeldet wurden. Das bedeutet jedoch nicht, dass die Verwendung des Jackson ObjectMapper standardmäßig ein Sicherheitsrisiko darstellt. In diesem Artikel erfahren Sie, wie Deserialisierungs-Schwachstellen in Jackson funktionieren und wie Sie sicherstellen, dass Sie nicht betroffen sind.
Bevor wir uns näher damit beschäftigen, beantworten wir zunächst einige Fragen, die Sie vielleicht haben …
Was ist Deserialisierung?
Bei der Deserialisierung werden Daten aus einer Datei oder einem Stream wieder in ein Objekt umgewandelt, das in Ihrer Anwendung verwendet werden kann. Dabei kann es sich um Binärdaten oder strukturierte Daten wie JSON und XML handeln. Deserialisierung ist das Gegenteil der Serialisierung, bei der Objekte in Byte-Streams oder strukturierten Text umgewandelt werden.
Wofür wird der Jackson ObjectMapper verwendet?
Der Jackson ObjectMapper ist Teil der Jackson-Bibliothek databind und dient dazu, JSON in Java-Objekte und umgekehrt umzuwandeln. Er gehört zu den meistgenutzten und bekanntesten Bibliotheken im Java-Ökosystem, um JSON in Java und zurück umzuwandeln, und wird automatisch mit Spring Boot ausgeliefert.
Ist der Jackson ObjectMapper sicher?
Ja, der Jackson ObjectMapper ist sicher und verwendet sichere Standardeinstellungen. Aktualisieren Sie unbedingt auf die neuesten Versionen, um bekannte Sicherheitsprobleme zu vermeiden.
Ist das Erstellen eines ObjectMapper aufwendig?
Das Erstellen eines ObjectMapper ist ziemlich aufwendig. Daher empfiehlt es sich, Ihre ObjectMapper-Instanz wiederzuverwenden. Der Jackson ObjectMapper ist threadsicher und kann deshalb problemlos wiederverwendet werden.
Java-Objekte aus JSON mit dem Jackson ObjectMapper erstellen
Mit dem folgenden Code können wir einen ObjectMapper erstellen und damit eine Person aus einem JSON-String rekonstruieren, der aus einer Datei stammt.
Das ist unkompliziert und es passiert nichts Besonderes. Ohne Annotationen verwendet der Jackson ObjectMapper Reflection, um das POJO-Mapping durchzuführen. Dank Reflection funktioniert dies unabhängig vom Zugriffsmodifizierer für alle Felder. Sind Getter und Setter vorhanden, verwendet der Jackson ObjectMapper diese für das Mapping.
Standardtypisierung in Jackson
Viele Schwachstellen in der Jackson-Bibliothek für die JSON-Serialisierung hängen von der Standardtypisierung ab, die nicht standardmäßig aktiviert ist. Sie müssen sie ausdrücklich aktivieren. Das bedeutet, dass die in dieser Liste aufgeführten Schwachstellen Ihr System in den meisten Fällen nicht direkt betreffen.
Doch zunächst erklären wir, was Standardtypisierung ist und wofür sie verwendet wird.
Die Standardtypisierung ist ein Mechanismus im Jackson ObjectMapper für den Umgang mit polymorphen Typen und Vererbung. Wenn Sie JSON in ein Java-POJO deserialisieren möchten, aber den Untertyp des Objekts oder Felds nicht kennen, können Sie einfach in die Oberklasse deserialisieren.
Angenommen, Sie haben Coffee und Tea. Beide Klassen haben dieselbe Oberklasse: HotDrink. Wenn Ihr Breakfast also ein HotDrink enthält, Sie aber nicht wissen, ob es sich um Coffee oder Tea handelt, können Sie das mit der Standardtypisierung lösen.
In diesem Beispiel habe ich die Standardtypisierung für den ObjectMapper aktiviert, damit ich überall, wo ich diesen ObjectMapper verwende, Polymorphie unterstützen kann. Sie können dies auch für ein bestimmtes Feld mit der Annotation @JsonTypeInfo tun.
Sicherheitsprobleme bei aktivierter Standardtypisierung im Jackson ObjectMapper
Ist die Standardtypisierung global aktiviert, lässt sich die Vererbung bis ins Extreme ausreizen. Wenn Ihr Breakfast kein HotDrink, sondern ein Feld vom Typ Object enthält, kann jedes Objekt im Classpath verfügbar sein. Das bedeutet auch, dass wir jedes im Classpath verfügbare Objekt deserialisieren können. Dabei könnte es sich um ein Gadget-Objekt handeln, das eine Gadget-Chain aufbaut, die letztlich in der Ausführung von Code aus der Ferne endet.
Diese Gadget-Chains ähneln stark denen, die ich in meinem Blogbeitrag Serialisierung und Deserialisierung in Java beschrieben habe. Vereinfachen wir das Ganze mit einem einzelnen Gadget, das bei der Initialisierung sofort einen Befehl ausführt. Meine Klasse SecondBreakfast unten enthält ein Getränk vom Typ Object.
Wenn ich mein SecondBreakfast bei aktivierter Standardtypisierung deserialisiere, kann ich ein Object deserialisieren, das beliebige Codeausführung ermöglicht.
Das ist ein vereinfachtes Beispiel. Eine Gadget-Chain zu finden und zu erstellen, ist zwar nicht einfach, aber durchaus möglich. Angesichts der vielen Bibliotheken und Frameworks, die wir verwenden, können Kombinationen aller Klassen in Ihrem Classpath eine solche Gadget-Chain bilden.
Außerdem ist bereits eine große Anzahl bekannter „bösartiger Klassen“ identifiziert. Die Deserialisierung einer solchen Klasse gilt als gefährlich und folgt im Wesentlichen dem oben beschriebenen Muster. Eine Übersicht finden Sie in der Liste der Deserialisierungs-Schwachstellen der Bibliothek jackson-databind in der Snyk Vulnerability Database.
Welche Auswirkungen hat das auf meine Anwendung?
Keine Panik, so schlimm ist es nicht. Erstens blockieren die Maintainer der Bibliothek jackson-databind aktiv die bekannten „bösartigen Klassen“ in der SubTypeValidator. Zweitens müssen Sie die Standardtypisierung ausdrücklich aktivieren. Diese Einstellung ist standardmäßig also deaktiviert, und eine polymorphe Deserialisierung ist gar nicht möglich.
Scans mit SCA-Tools wie Snyk zeigen die Schwachstelle in den Scan-Ergebnissen an. Eine kurze Suche zeigt, dass es in der Vergangenheit viele solcher Probleme gab. Es ist immer ratsam, auf die neueste Version zu aktualisieren, denn die Bibliothek wird gut gepflegt und neue „bösartige Klassen“ werden nach ihrer Entdeckung aktiv blockiert. Am besten verhindern Sie jedoch, dass die Standardtypisierung für Ihren Jackson-ObjectMapper aktiviert wird.
Der Snyk Triage Assistant hilft weiter
Snyk arbeitet derzeit daran, diese Schwachstellen herauszufiltern, wenn Ihr Code die erforderlichen Voraussetzungen nicht erfüllt. Beim Jackson ObjectMapper bedeutet das: Wenn Ihr Code keine polymorphe Typisierung aktiviert, zeigen wir Ihnen an, dass diese konkrete Schwachstelle Sie wahrscheinlich nicht gefährden kann. Zum Zeitpunkt der Veröffentlichung ist diese Funktion nur für die Jackson-Deserialisierungs-Schwachstelle verfügbar. Das Team arbeitet jedoch weiter daran, sie zu verbessern und auszubauen. Um diese Funktion zu nutzen, benötigen wir Ihre Zustimmung, Ihren Code zu scannen und zu prüfen, ob die Standardtypisierung deaktiviert ist.

Die Codebeispiele aus diesem Blogbeitrag finden Sie auf meinem GitHub-Konto. Sie können die Beispiele gerne forken oder nach Belieben wiederverwenden.
Deserialisieren Sie sicher!
Am besten vermeiden Sie Deserialisierungsprobleme mit dem Jackson ObjectMapper, indem Sie polymorphe Typisierung verhindern. Aktivieren Sie die Standardtypisierung für Ihren ObjectMapper bitte nicht. Verbinden Sie Ihr Projekt außerdem mit Snyk, um herauszufinden, ob Sie eine jackson-databind-Bibliothek mit bekannten Schwachstellen verwenden. In den meisten Fällen lässt sie sich problemlos durch eine neuere Version ersetzen. Wenn Sie das Code-Scanning aktivieren, hilft Ihnen der Triage Assistant dabei, einzuschätzen, ob eine Schwachstelle wahrscheinlich oder eher unwahrscheinlich ausnutzbar ist.
Starten Sie mit Capture-the-Flag
Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Challenges lösen.
