Zum Inhalt springen
OneKitly

JSON ist einfacher, als du denkst — und genau das ist das Problem

Veröffentlicht am 8.8.2025 · 18 Min. Lesezeit · Entwickler-Tools

Daniel Okonkwo

Daniel OkonkwoFront-end-Entwickler und Tech-Redakteur bei OneKitly

Web-Performance · Dateiformate

Anhand von 7 Quellen geprüft

Profil ansehen
Kurz gesagt

Die Grammatik von JSON passt auf eine Seite, und genau deshalb ist sie undicht. ECMA-404 und RFC 8259 definieren sechs Wertarten — Objekt, Array, Zeichenkette, Zahl, true oder false, null — und sonst nichts. Es gibt keinen Ganzzahltyp: JSON hat einen einzigen Zahlentyp, und ein JavaScript-Parser legt ihn auf ein IEEE-754-Double, weshalb 1234567890123456789 als das Double 1234567890123456768 zurückkommt, ein Fehler von 21, während Pythons Parser den Wert exakt liefert. Dieselben Bytes, zwei verschiedene Werte. Es gibt keinen Datumstyp: Ein Zeitstempel ist eine Zeichenkette, deren Format bloß eine Konvention ist. NaN und Infinity lassen sich gar nicht hinschreiben — JSON.stringify macht null daraus und JSON.parse weist die Literale zurück, obwohl Pythons json-Modul sie standardmäßig ausgibt und damit Dokumente erzeugt, die kein JSON sind. Die negative Null überlebt asymmetrisch: -0 zu parsen ergibt -0, -0 zu serialisieren ergibt 0. Doppelte Schlüssel sind in der Grammatik erlaubt, RFC 8259 sagt nur, das Ergebnis sei unvorhersehbar, und jeder verbreitete Parser behält stillschweigend den letzten. Kommentare kommen in der Grammatik überhaupt nicht vor. Ein generiertes JSON Schema legt die Form fest, nie die Bedeutung, und eines aus einer einzigen Stichprobe überanpasst massiv. Und die Schlüsselreihenfolge ist eine Tatsache auf Byte-Ebene: Vertausche zwei, und die Nutzlast hasht anders — womit Signaturen brechen.

JSON hat keinen Ganzzahltyp, keinen Datumstyp, keine Kommentare und kein Schema. Jede dieser Lücken erzeugt einen konkreten Fehler: Eine 19-stellige ID kommt um 21 verfälscht zurück, ein Zeitstempel wird zu einer Zeichenkette, auf die sich niemand geeinigt hat, NaN lässt sich nicht hinschreiben, und doppelte Schlüssel sind erlaubt. Alles ausgeführt, in zwei Sprachen.

Sechs Wertarten, und keine ist die gesuchte

JSON ist zweimal spezifiziert, in ECMA-404 und in RFC 8259, und beide Dokumente sind kurz, weil es sehr wenig zu sagen gibt. Ein Wert ist ein Objekt, ein Array, eine Zeichenkette, eine Zahl, das Literal true, das Literal false oder das Literal null. Das ist das gesamte Typsystem. Alles Übrige, was du in JSON vermutest, hat deine Sprache beim Hinein- oder Hinausgehen ergänzt.

Zähle die Lücken. Kein Ganzzahltyp, nur eine einzige Zahlenproduktion, die ein Parser auf den Zahlentyp abbilden muss, den er hat. Kein Datum, keine Uhrzeit, keine Dauer. Kein Binärtyp — du bekommst Base64 in einer Zeichenkette, was ein Drittel mehr Bytes kostet. Keine Kommentare. Keine Aufzählungen, keine Bereiche, keine Pflichtfelder, überhaupt kein Schema. Keine Zusicherung zur Schlüsselreihenfolge. Keine Möglichkeit, auf einen anderen Teil desselben Dokuments zu verweisen — ein Graph muss von Hand flachgeklopft werden.

Nichts davon ist ein Konstruktionsfehler. JSON wurde aus einer JavaScript-Literalsyntax herausgelöst, um Daten zwischen zwei Programmen zu bewegen, die sich über deren Bedeutung bereits einig waren, und diese Aufgabe erledigt es in einer Größe und Geschwindigkeit, die nichts übertroffen hat. Der Fehler entsteht, wenn ein Format, das keine Bedeutung trägt, so verwendet wird, als trüge es welche. Alles Folgende ist ein Fall dieses Fehlers.

Die Zahl, die falsch zurückkommt

Die Zahlengrammatik von JSON erlaubt jede Dezimalzahl, die du hinschreiben kannst. RFC 8259 warnt, dass Implementierungen sich unterscheiden, und empfiehlt, innerhalb der IEEE-754-Doppelgenauigkeit zu bleiben — praktisch also Ganzzahlen bis 2^53 − 1 = 9 007 199 254 740 991. Darüber können Doubles keine aufeinanderfolgenden Ganzzahlen mehr darstellen, und ein JavaScript-Parser hat keinen anderen Ort für den Wert.

Führ es aus. JSON.parse('9007199254740993') liefert 9007199254740992 — die Eingabe war ungerade, die Ausgabe ist gerade, und es wurde kein Fehler ausgelöst. Nimm eine realistische 19-stellige Kennung, wie sie soziale Plattformen und Chatdienste vergeben: JSON.parse('{"id": 1234567890123456789}') speichert das Double 1234567890123456768, das JavaScript anschließend als 1234567890123456800 ausgibt, weil das die kürzeste Dezimalzahl ist, die auf dasselbe Double zurückführt. Die empfangene Kennung weicht von der gespeicherten um 21 ab und von der ausgegebenen um 32. Eine kürzere 18-stellige ID, 175928847299117063, kommt als 175928847299117060 zurück.

Gib nun dieselben Bytes an Python 3.13: json.loads liefert exakt 1234567890123456789 als Python-int, weil Pythons Parser die JSON-Zahlenproduktion auf eine Ganzzahl beliebiger Genauigkeit abbildet, sofern kein Nachkommateil vorliegt. Ein Dokument, zwei Sprachen, zwei verschiedene Werte — und beide Parser sind konform. Das ist das ganze Problem in einer Zeile: JSON sagt einem Parser nicht, welchen Zahlentyp er nehmen soll, also entscheidet der Parser, und die Entscheidung fällt nicht überall gleich aus.

Dasselbe Loch verschluckt die Unterscheidung Ganzzahl/Dezimalzahl in der Gegenrichtung. JSON.stringify(1.0) erzeugt die zwei Zeichen "1", sodass ein Feld, das deine Datenbank als Dezimalzahl deklariert hat, als etwas ankommt, das ein Schemagenerator als Ganzzahl etikettiert. Es gibt keine Möglichkeit, 1.0 in JSON zu schreiben und es über einen JavaScript-Rundlauf 1.0 bleiben zu lassen. Die Abhilfe für Kennungen ist grob und universell: Verschicke sie als Zeichenketten. Die früh gebissenen Plattformen liefern beide Felder — eine numerische und eine textuelle ID — genau deshalb, weil sie ihre Clients nicht reparieren konnten.

Daten, NaN, Infinity und ein Minuszeichen, das verschwindet

JSON.stringify(new Date(...)) erzeugt "2026-08-28T14:30:00.000Z", was aussieht, als verstünde JSON Daten. Tut es nicht. ECMAScript definiert Date.prototype.toJSON, und JSON.stringify ruft es auf; das Ergebnis ist eine gewöhnliche Zeichenkette. Parse sie zurück, und typeof liefert "string". Das Format ist zufällig jenes, das RFC 3339 aus ISO 8601 herausschneidet, doch nichts in JSON verlangt es — und sobald ein zweiter Dienst mit einer anderen Bibliothek serialisiert, bekommst du ein Datum in anderer Gestalt: eine Epoch-Ganzzahl, eine Lokalzeit ohne Versatz, eine "/Date(1234567890)/"-Verpackung aus einem älteren Stack. Jede davon ist gleichermaßen gültiges JSON und ohne vorherige Absprache gleichermaßen unlesbar.

NaN und die beiden Unendlichkeiten stehen nicht in der Grammatik, lassen sich also gar nicht hinschreiben. JSON.stringify({a: NaN, b: Infinity, c: -Infinity}) liefert {"a":null,"b":null,"c":null} — drei verschiedene Gleitkommawerte, stillschweigend auf ein einziges null zusammengefaltet. JSON.parse('{"a":NaN}') wirft einen SyntaxError. In einem Array werden auch undefined, Funktionen und Symbole zu null; als Objektwerte entfallen sie ganz, sodass {a: undefined, b: 1} zu {"b":1} serialisiert und ein Schlüssel schlicht verschwindet.

Python macht etwas Schlimmeres und Interessanteres: json.dumps({'a': nan, 'b': inf}) gibt standardmäßig {"a": NaN, "b": Infinity} aus, und json.loads liest es klaglos zurück. Diese Ausgabe ist kein JSON. Sie durchquert deine eigenen Python-Dienste unbeschadet und scheitert in dem Moment, in dem sie einen konformen Parser in irgendeiner anderen Sprache erreicht — meist der Browser, meist die Produktion. Den Schalter gibt es: allow_nan=False wirft stattdessen eine Ausnahme — und fast niemand setzt ihn.

Die negative Null ist die kleinste und seltsamste der Reihe. IEEE 754 hat zwei Nullen, und sie zählen dort, wo ein Vorzeichen Information trägt — eine Änderungsrate, eine Rundungsrichtung, ein Saldo, der von unten exakt auf nichts kam. JSON.parse('-0') liefert -0: Object.is(JSON.parse('-0'), -0) ist true, und 1 geteilt durch diesen Wert ergibt −Infinity. JSON.stringify(-0) liefert dagegen das einzelne Zeichen 0. Der Wert überlebt also in einer Richtung und in der anderen nicht, und ein vollständiger Rundlauf kippt 1 ÷ x ohne jede Warnung von −Infinity auf +Infinity.

Doppelte Schlüssel sind erlaubt, und jeder Parser wählt still einen aus

Die JSON-Grammatik definiert ein Objekt als kommagetrennte Folge von Name-Wert-Paaren. Sie sagt nicht, dass die Namen verschieden sein müssen. RFC 8259 behandelt das in Prosa statt in der Grammatik: Namen SOLLTEN eindeutig sein, und der Text warnt, dass Implementierungen bei einem Duplikat unterschiedlich reagieren — manche nehmen den letzten, manche den ersten, manche melden einen Fehler. Dieses SOLLTEN ist das schwächste Wort, das die RFC hätte wählen können, und es bedeutet, dass jeder Parser, dem du je begegnest, das Dokument annimmt.

In der Praxis ist der Mainstream konvergiert. JSON.parse('{"role":"admin","role":"user"}') liefert in Node {"role":"user"}, und Pythons json.loads liefert dasselbe. Der letzte gewinnt, ohne Warnung, ohne Möglichkeit, im Nachhinein festzustellen, dass das Dokument je zwei hatte. Die Information über das Duplikat wird vom Parsen selbst vernichtet — und genau das macht die Fehlersuche schwer: Wenn dein Code das Objekt sieht, ist der Beweis weg.

Die ernst zu nehmende Folge: Ein Dokument kann für die Komponente, die es prüft, etwas anderes bedeuten als für die Komponente, die daraufhin handelt — wenn beide Parser verwenden, die sich uneinig sind, oder wenn die eine den Rohtext und die andere das geparste Objekt betrachtet. Die allgemeine Gestalt dieser Gefahr und die daraus folgende Regel behandelt der Artikel dieser Seite zur Prüfung signierter Token: Validiere und handle auf derselben geparsten Repräsentation, nie auf zweien. Die konkrete Abhilfe hier ist einfacher. Weise Dokumente mit doppelten Namen schon am Eingang zurück, bevor irgendetwas anderes sie ansieht; ein Streaming-Parser oder ein vorgeschalteter Tokenisierungslauf sieht das Duplikat, das JSON.parse wegwirft.

Was ein generiertes Schema bringt — und wo es überanpasst

JSON Schema füllt die größte Lücke: Es ist ein Vokabular dafür, welche Schlüssel vorhanden sein müssen, welchen Typ jeder Wert hat, welche Werte zulässig sind und wie tief die Verschachtelung geht. Ein Validator macht aus einem formlosen Dokument am Rand deines Systems ein Ja oder ein Nein, und das ist viel wert. Einen ersten Entwurf aus einer Stichprobe zu erzeugen, die du ohnehin hast, ist der schnellste Weg dorthin — und genau das tut der Schemagenerator dieser Seite.

Die Falle: Ein aus einem einzigen Dokument abgeleitetes Schema beschreibt dieses Dokument, nicht die Familie, zu der es gehört. Nimm eine harmlos wirkende Stichprobe: ein Objekt mit ganzzahliger id 42, einem Namen, einem einelementigen Array von Text-Tags, einem ganzzahligen score von 10, einem manager, der zufällig null ist, und einem Boolean. Ein naiver Generator erzeugt Typ integer für id und score, Typ null für manager, ein Array von Zeichenketten für tags, alle Schlüssel in required und additionalProperties false.

Validiere nun fünf völlig legitime spätere Dokumente dagegen. Ein score, der als 10.5 eintrifft, wird abgelehnt, weil die Stichprobe zufällig ganzzahlig war. Ein manager, der endlich mit einem Objekt gefüllt ist, wird abgelehnt, weil die Stichprobe zufällig null war. Ein Dokument, das ein optionales Feld auslässt, wird abgelehnt, weil der Generator alle Schlüssel in required gesetzt hat. Ein Dokument mit einem neuen email-Feld wird abgelehnt, weil additionalProperties false war. Ein tags-Array mit einer Zahl darin wird abgelehnt. Fünf von fünf — und jedes davon ist ein echter Datensatz, den dein System hätte annehmen müssen.

Die andere Hälfte der Lehre ist, was dasselbe Schema bereitwillig durchlässt: Ein Datensatz mit leerem Namen und einem score von −999 besteht jede Prüfung, denn JSON Schema validiert Form und nie Bedeutung. Nichts im Vokabular weiß, dass ein Name nicht leer sein sollte oder dass ein score eine Untergrenze hat. Nutze die Generierung also als ersten Entwurf und bearbeite ihn dann von Hand: weite integer überall dort zu number, wo eine Dezimalzahl möglich ist, ersetze einen null-Typ durch eine nullable Union, kürze required auf die wirklich verpflichtenden Felder, lasse additionalProperties offen, sofern du den Vertrag nicht bewusst verriegelst, und ergänze die minLength-, minimum- und enum-Bedingungen, die deine echten Geschäftsregeln tragen.

Schlüsselreihenfolge und die Signatur, die nicht mehr passt

JSON-Objekte sind als Datenmodell ungeordnet, aber ein JSON-Dokument ist eine Bytefolge, und Bytes haben eine Reihenfolge. JSON.stringify gibt Zeichenketten-Schlüssel in Einfügereihenfolge aus — mit einer Ausnahme, über die viele stolpern. ECMAScript stellt Ganzzahl-Indexschlüssel aufsteigend voran, noch vor jeden Zeichenketten-Schlüssel. Baue ein Objekt, indem du z, dann user_2, dann "2", dann user_1, dann "1" zuweist: stringify liefert {"1":5,"2":3,"z":1,"user_2":2,"user_1":4}. Die beiden zahlenähnlichen Schlüssel sind nach vorn gesprungen und haben sich numerisch sortiert; der Rest blieb in der geschriebenen Reihenfolge. Das Parsen macht dasselbe, also kommt ein Dokument, das du in einer Reihenfolge empfangen hast, in einer anderen aus JSON.parse heraus.

Zum Produktionsvorfall wird das in dem Moment, in dem du eine Nutzlast hashst. Zwei Dienste beschreiben dieselbe Überweisung über 100 €: Der eine schreibt {"amount":100,"currency":"EUR","to":"acct_9"}, der andere dieselben drei Felder, beginnend mit "to". Die Objekte sind tief gleich. Die SHA-256-Digests lauten 1648f3b9016a5b95… und bc654befe505d093…, und ein darüber berechneter HMAC unterscheidet sich schon im ersten Byte. Der Empfänger weist eine Anfrage zurück, die semantisch exakt jene ist, die er erwartet hat.

Die Schlüssel vor dem Serialisieren zu sortieren, behebt genau diesen Fall — beide Objekte kanonisieren zur amount-zuerst-Form, und die Digests stimmen überein. Sortieren allein ist aber keine kanonische Form, denn derselbe Wert lässt sich weiterhin auf mehrere Arten schreiben: "é" und "\u00e9" sind dieselbe Zeichenkette und verschiedene Bytes, 1e21 und 1000000000000000000000 sind dieselbe Zahl, und ein Serialisierer mag den Schrägstrich maskieren oder auch nicht. RFC 8785, das JSON Canonicalization Scheme, ist die normierte Antwort: Sie legt die Schlüsselreihenfolge nach UTF-16-Codeeinheit fest, bindet die Zahlenformatierung an die ECMAScript-Regeln und bestimmt genau, welche Zeichen maskiert werden. Wenn du das Problem ganz vermeiden kannst, tu es: Signiere und prüfe exakt die Bytes, die du empfangen hast, und serialisiere ein Dokument, das du gleich prüfen willst, niemals neu.

Die praktische Checkliste

Verschicke jede Kennung als Zeichenkette, egal welchen Typ sie in deiner Datenbank hat. Einigt euch schriftlich auf ein einziges Zeitstempelformat — RFC 3339 mit explizitem Versatz ist am wenigsten umstritten — und weise alles andere an der Grenze zurück, statt zu raten. Lege vorab fest, was ein fehlender Wert bedeutet, und wähle entweder null oder Abwesenheit, nicht beides. Lass nie einen NaN oder eine Unendlichkeit bis zum Serialisierer gelangen; wandle sie bewusst dort, wo gerechnet wird, in null, in eine Zeichenkette oder in einen Fehler um.

Weise doppelte Namen am Eingang zurück. Generiere ein Schema, um Tipparbeit zu sparen, und bearbeite es, bevor du ihm traust. Kanonisiere, oder signiere Rohbytes — nie ein neu serialisiertes Objekt. Und halte Konfigurationsdateien, wo Menschen Kommentare und abschließende Kommas brauchen, in einem Format, das beides hat — das ist das Thema des nächsten Artikels.

Dasselbe JSON-Dokument, gelesen von zwei konformen Parsern — Node v26.3.0 und Python 3.13.2
Im DokumentNode liefertPython liefertFolge
900719925474099390071992547409929007199254740993 (exakt)Ungerade Zahl wird gerade, ohne Fehler
12345678901234567891234567890123456768, ausgegeben als 12345678901234568001234567890123456789 (exakt)Kennung um 21 daneben; die beiden Dienste sind uneins
1.01, und JSON.stringify schreibt es als "1" zurück1.0 als Float, zurückgeschrieben als 1.0Unterscheidung Dezimal/Ganzzahl nur in einer Sprache verloren
Ein serialisiertes Date, "2026-08-28T14:30:00.000Z"Eine Zeichenkette (typeof ist "string")Eine ZeichenketteEs gibt keinen Datumstyp; das Format ist Konvention
NaN als Literal geschriebenSyntaxError — abgelehntnan — akzeptiert und standardmäßig ausgegebenPython schreibt Dokumente, die kein JSON sind
-0, aus einem Programm serialisiertAls 0 geschrieben; das Vorzeichen ist wegAls -0.0 geschrieben; das Vorzeichen bleibt1 ÷ x kippt von −Infinity auf +Infinity
{"role":"admin","role":"user"}role = user (der letzte gewinnt)role = user (der letzte gewinnt)Grammatisch erlaubt, laut RFC 8259 unvorhersehbar
JSON-Schema-GeneratorVerwandle ein JSON-Beispiel in ein JSON Schema. Füge ein Objekt, ein Array oder zeilenweise Datensätze ein: es leitet Typen, Eigenschaften und Array-Formen ab, führt die in den Objekten gesehenen Felder zu einer Pflichtliste zusammen und erkennt gängige String-Formate — E-Mail, URL, UUID, Datum und Datum-Zeit — in Draft 2020-12, 2019-09 oder Draft-07.Tool ausprobieren

Häufige Fragen

Wie bringe ich eine 64-Bit-Kennung durch JSON, ohne Ziffern zu verlieren?
Verschicke sie als Zeichenkette. Das ist die einzige Abhilfe, die überall funktioniert, und deshalb veröffentlichen die zuerst gebissenen Plattformen zwei Felder — eine numerische ID und eine Textfassung derselben ID —, statt ihre Clients zu zerbrechen. Ein JSON.parse-Reviver hilft dir nicht: Der Reviver läuft, nachdem der Tokenizer das Double bereits erzeugt hat, sodass die Ziffern schon weg sind, wenn dein Callback den Wert sieht. Bigint-fähige Parser existieren und funktionieren, weil sie den Tokentext lesen und den Typ selbst bestimmen — aber sie ändern, was dein Code bekommt, und jeder nachgelagerte Vergleich, jedes JSON.stringify und jede Rechnung muss geprüft werden. Kannst du den Erzeuger nicht ändern, erkenne wenigstens den Schaden: Eine Ganzzahl, deren Betrag Number.MAX_SAFE_INTEGER, 9007199254740991, übersteigt, ist nicht mehr vertrauenswürdig, und ein Rundlauf über String(BigInt(x)) im Vergleich mit dem Rohtoken sagt dir, ob sie überlebt hat. Und wenn du auf Zeichenketten umstellst: Textkennungen sortieren lexikografisch, "10" kommt vor "9" — jede Ordnung, auf die du dich verlassen hast, muss in ein separates numerisches Feld oder in die Datenbank wandern.
Sind doppelte Schlüssel wirklich gültiges JSON?
Ja, grammatisch. Weder ECMA-404 noch die Grammatik in RFC 8259 verbietet einen wiederholten Namen, ein Dokument damit lässt sich also parsen. RFC 8259 ergänzt eine Prosa-Anforderung auf SOLLTE-Ebene — Namen sollten eindeutig sein — und warnt, dass Implementierungen andernfalls unterschiedlich reagieren; genannt werden drei plausible Verhaltensweisen: den letzten behalten, den ersten behalten oder einen Fehler melden. Hier gemessen behalten Nodes JSON.parse und Pythons json.loads beide den letzten, sodass {"role":"admin","role":"user"} in beiden die Rolle user liefert. Weil das Parsen selbst den Beweis verwirft, lässt sich das Duplikat am Ergebnisobjekt nicht mehr erkennen, und keine spätere Validierung findet es. Die praktische Regel lautet: am Eingang zurückweisen — entweder mit einem Streaming- oder ereignisbasierten Parser, der jeden Namen beim Auftreten meldet, oder mit einem billigen vorgeschalteten Tokenisierungslauf, der Namen pro Objekt zählt, und dann die Anfrage ablehnen. Ein Schema erledigt das nicht für dich: JSON Schema arbeitet auf der geparsten Instanz, und da ist das Duplikat längst aufgelöst.
JSON hat keine Kommentare. Was nehme ich für Konfigurationsdateien?
Kommentare wurden bewusst weggelassen, mit der Begründung, dass Leute anfangen würden, Parsing-Direktiven hineinzuschreiben. Abschließende Kommas, einfach gequotete Zeichenketten und Schlüssel ohne Anführungszeichen fehlen aus demselben Grund: Die Grammatik ist klein, damit jede Implementierung übereinstimmt. Das ist eine gute Eigenschaft für Daten auf der Leitung und eine miserable für eine Datei, die ein Mensch pflegt. Die ehrliche Aufteilung: striktes JSON für alles, was eine Maschine erzeugt oder überträgt, und etwas Freundlicheres für alles, was ein Mensch bearbeitet. JSONC — JSON mit Kommentaren — akzeptieren mehrere Editoren und Toolchains und ist der kleinste Schritt zur Seite. JSON5 ergänzt abschließende Kommas, Schlüssel ohne Anführungszeichen, einfache Anführungszeichen, Hexadezimalzahlen und die Literale NaN und Infinity, die JSON fehlen. TOML ist eigens für Konfiguration entworfen und hat echte Daten. YAML ist am weitesten verbreitet und ist Thema des nächsten Artikels dieser Reihe, samt der Arten, wie seine Typinferenz dich überraschen wird. Das Einzige, was man nicht tun sollte, ist ein "_comment"-Schlüssel: Er ist erlaubt, er übersteht Rundläufe, und er übersteht sie auch in das, was du als Nächstes serialisierst — wo ihn niemand erwartet.
Ersetzt ein generiertes Schema handgeschriebene Validierung?
Nein, aus zwei getrennten Gründen. Erstens überanpasst die Generierung: Oben gemessen, wies ein aus einem einzigen Datensatz abgeleitetes Schema fünf von fünf legitimen späteren Datensätzen zurück — eine Dezimalzahl, wo die Stichprobe ganzzahlig war, ein gefülltes Feld, wo die Stichprobe null war, ein fehlendes optionales Feld, ein hinzugekommenes Feld und ein Array mit gemischten Typen. Jedes davon ist eine normale Weiterentwicklung einer echten Nutzlast. Zweitens validiert JSON Schema von Haus aus Form und nicht Bedeutung, weshalb dasselbe Schema einen Datensatz mit leerem Namen und einem score von −999 anstandslos akzeptierte. Wofür Generierung wirklich taugt, ist der mühsame Teil: fünfzig Schlüssel samt Typen ohne Tippfehler aufzuzählen und dir eine Startdatei zu geben, die bereits parst. Behandle die Ausgabe als Entwurf und mache vier Änderungen, bevor du ihr traust — weite integer überall dort zu number, wo eine Dezimalzahl vorkommen kann, mache nullbare Felder zu einer Union statt zum null-Typ, stutze required auf das wirklich Verpflichtende und entscheide bewusst, ob additionalProperties false sein soll. Ergänze dann die Bedingungen, die die Geschäftsregeln tragen, denn genau die kann kein Generator aus Daten erschließen.
Warum berechnen zwei Dienste unterschiedliche Hashes derselben Nutzlast?
Weil ein Hash über Bytes läuft und die beiden Dienste für denselben Wert unterschiedliche Bytes erzeugt haben. Drei Dinge variieren unabhängig. Die Schlüsselreihenfolge ist der übliche Schuldige: Zwei tief gleiche Objekte serialisieren unterschiedlich, wenn ihre Schlüssel in anderer Reihenfolge eingefügt wurden, und ECMAScript zieht zusätzlich ganzzahlindex-ähnliche Schlüssel aufsteigend nach vorn, sodass "2" und "10" allen anderen vorangehen, egal wo du sie geschrieben hast. Das String-Escaping ist das zweite: "é" direkt geschrieben und als \u00e9 geschrieben sind dieselbe Zeichenkette und verschiedene Bytes, und Serialisierer sind sich beim Schrägstrich und den beiden Zeilentrennern U+2028 und U+2029 uneinig. Die Zahlenformatierung ist das dritte: 1e21 und seine lange Dezimalform bezeichnen dasselbe Double, und 1.0 serialisiert als 1. Die richtige Abhilfe hängt davon ab, wo du stehst. Prüfst du etwas Empfangenes, hashe exakt die angekommenen Bytes und serialisiere sie nie neu — das umgeht alle drei Probleme auf einmal. Musst du einen selbst konstruierten Wert hashen, nimm eine definierte kanonische Form: RFC 8785 spezifiziert eine, die Schlüsselreihenfolge, Zahlenformatierung und Escaping gemeinsam festlegt, und Bibliotheken setzen sie in den meisten Sprachen um.
Ist JSON.parse bei nicht vertrauenswürdiger Eingabe sicher?
Strukturell ja, und weit sicherer als das eval, das es abgelöst hat: Die Grammatik enthält keine ausführbare Konstruktion, ein geparstes Dokument kann also keinen Code ausführen. Zwei konkrete Sorgen tauchen auf, und beide sind weniger alarmierend als ihr Ruf. Prototype Pollution wird nicht von JSON.parse verursacht — die Spezifikation verlangt das Anlegen von Dateneigenschaften, sodass JSON.parse('{"__proto__": {"admin": true}}') ein Objekt mit einer gewöhnlichen eigenen Eigenschaft namens __proto__ liefert und Object.prototype unberührt lässt; hier geprüft, ist ({}).admin weiterhin undefined. Die Verschmutzung passiert danach, in einer naiven rekursiven Zusammenführung oder einer ungeschützten Zuweisungsschleife, die diese Schlüssel durchläuft — dorthin gehört die Absicherung. Ein Stapelüberlauf durch tiefe Verschachtelung ist ebenfalls weitgehend Geschichte: V8s Parser ist iterativ, und eine Million Ebenen verschachtelter Arrays parsten unter Node 26 fehlerfrei. Wirklich begrenzenswert bleiben Größe und Zeit. Ein Parser muss das ganze Dokument lesen, bevor er irgendetwas liefert, ein unbeschränkter Body bedeutet also unbeschränkten Speicher, und doppelte Schlüssel, überdimensionierte Zahlen und unerwartete Felder müssen weiterhin an der Grenze zurückgewiesen werden. Deckle den Request-Body, dann validiere.

Artikel, die dich interessieren könnten

Alle Ratgeber
RatgeberSQL-Formatierung und die IN-Klausel, die die Produktion zerlegtEine IN-Liste per Zeichenkettenverkettung zu bauen ist zugleich der klassische Injektionsvektor und eine Leistungsklippe. Parametrisierung behebt das Erste strukturell, weil der Plan kompiliert wird, bevor irgendein Wert eintrifft. Das Zweite verlangt Rechnen: die von den Herstellern dokumentierten Parameterobergrenzen und das, was eine Abfrage, deren Text sich mit jeder Listenlänge ändert, mit einem Plan-Cache anstellt.ErklärungYAML wirkt freundlich und beißtYAML ist JSON plus eine Schicht Typinferenz, und die Inferenz ist der gefährliche Teil. Dieselbe Datei durch einen YAML-1.2- und einen YAML-1.1-Parser geschickt: no ist im einen eine Zeichenkette und im anderen false, 01234 ist im einen 1234 und im anderen 668, und 12:30:00 ist in einem von beiden eine Zahl.ErklärungJSON zu CSV bei verschachtelter Struktur: warum es keine richtige Antwort gibtDieselben zwei Bestellungen kommen aus einem Konverter mit fünf Spalten und aus einem anderen mit zehn, und keiner liegt falsch. Punktpfade, Arrays aus Skalaren, Arrays aus Objekten und Datensätze mit unterschiedlichen Schlüsseln — vier Entscheidungen, für dich getroffen, meist stillschweigend.ErklärungXML zu JSON: Attribute, Wiederholung und die Falle des einelementigen ArraysZwei Dokumente, die sich nur in der Zahl der Kinder unterscheiden, ergeben zwei verschiedene JSON-Formen, und ohne Schema kann kein Konverter sie auseinanderhalten. Dazu, was dieser wirklich mit Attributen, gemischtem Inhalt und Leerraum macht — und das Einzige, was er weiterhin nicht festhalten kann.ErklärungCSV zu JSON: die fünf Fälle, an denen jeder Konverter scheitertTrennzeichen in Anführungszeichen, eingebettete Zeilenumbrüche, mehrdeutige Typen, doppelte Spaltennamen und Kodierung. Jeder Fall lief durch den Konverter, und die exakte Ausgabe steht hier — auch die beiden, die er nicht rettet.VergleichJSON vs. XML: Was ist der Unterschied?JSON und XML speichern beide strukturierte Daten als Text, aber mit anderen Kompromissen. Hier steht, wie jedes aussieht, wo jedes gewinnt und wie du wählst.

Ähnliche Tools

Quellen

Hast du einen Fehler in diesem Artikel entdeckt?