HandyTools Hub

← Alle Anleitungen

Der komplette Leitfaden zu YAML-Fallen: Vom Norwegen-Problem bis zu unsicheren Loadern

2026-08-06

Öffnen Sie irgendein Kubernetes-Manifest, einen GitHub-Actions-Workflow oder eine Docker-Compose-Datei, und Sie schauen auf YAML. Es bezeichnet sich selbst als „menschenfreundliches Datenserialisierungsformat“, und es ist wirklich angenehmer zu schreiben als JSON: keine Anführungszeichen, keine Klammern, keine Kommas. Der Preis, den Sie zahlen, ist, dass der Parser in Ihrem Namen viele implizite Typvermutungen anstellt — und diese Vermutungen sind häufig falsch. Schreiben Sie no, und Sie erhalten vielleicht false; schreiben Sie Version 1.10, und Sie erhalten vielleicht den Float 1.1. Diese Anleitung geht die YAML-Fallen durch, die Menschen in der Produktion tatsächlich verletzen, und die Abhilfen, die wirklich funktionieren.

YAML ist ein JSON-Superset (meistens)

Eines der Designziele von YAML war, ein Superset von JSON zu sein: Nahezu alles gültige JSON ist gültiges YAML. Das ist sowohl JSON als auch YAML:

{"name": "app", "replicas": 3, "debug": true}

Es gibt ein nützliches Korollar: Wann immer Sie unsicher sind, wie man etwas in YAML schreibt, können Sie direkt in JSON-Syntax innerhalb der YAML-Datei wechseln — Anführungszeichen und Klammern hinzufügen, und das Verhalten wird eindeutig. Aber die „Superset“-Behauptung schneidet in beide Richtungen. YAML erlaubt weit mehr als JSON, und dasselbe Dokument kann wilde verschiedene Typen erzeugen, je nachdem, welcher Parser es liest. Beim Debuggen einer Konvertierung ist der YAML-zu-JSON-Konverter der schnellste Weg zu sehen, was ein Parser tatsächlich vermutet hat — erweitern Sie das YAML zu JSON, und jede implizite Konvertierung wird sichtbar.

Das Norwegen-Problem: Wenn no false bedeutet

Das ist YAMLs berühmteste Falle, berühmt genug, um einen Namen zu haben: das Norwegen-Problem. Die YAML-1.1-Spezifikation definiert eine großzügige Menge boolescher Synonyme: y, n, yes, no, on, off, true, false plus ihre großgeschriebenen Varianten — alle als Boolesche Werte geparst.

Der Haken: NO ist auch Norwegens ISO-3166-Ländercode. Schreiben Sie eine unquotierte Liste von Ländern:

countries:
  - CN
  - US
  - NO

Ein YAML-1.1-konformer Parser reicht Ihnen ["CN", "US", false]. Kein Fehler, keine Warnung — die Daten ändern sich einfach still. Dasselbe Schicksal erwartet Toggle-Einstellungen mit Namen on:/off: und Umfrageantworten, die als yes geschrieben sind.

Präzise zur Spezifikationsgeschichte: Das ist YAML-1.1-Verhalten. YAML 1.2 verschärfte die Regeln, sodass nur true und false Boolesche Werte sind. Aber viele weit genutzte Parsing-Bibliotheken (ältere PyYAML, bestimmte Ruby-Versionen) nutzen weiterhin standardmäßig 1.1-Semantik, das Problem ist also sehr lebendig. Die einzig verlässliche Abhilfe ist eine Regel: Quotieren Sie jeden Skalar, der ein String sein könnte — "NO", "no", "off" sind immer Strings.

Versionsnummern werden Floats: 1.10 ist nicht 1.10

Zeigen Sie einem YAML-Parser 1.10, und er behandelt es bedenkenlos als Float — und die Floats 1.10 und 1.1 sind dieselbe Zahl. Ihre Dependency-Pins, API-Versionen und Release-Tags werden alle korrumpiert:

dependencies:
  mylib: 1.10   # als 1.1 geparst

Der gemischte Fall ist heimtückischer: 1.9 wird der Float 1.9, 1.10 wird 1.1, und v1.10 — wegen des Buchstabens — bleibt ein String. Eine Liste, drei verschiedene Typen, und Ihre Sortier- und Vergleichslogik bricht still. Jede Versionsnummer sollte ein String sein: version: "1.10".

Der sexagesimale Geist

YAML 1.1 hat ein Feature, das fast niemand kennt: sexagesimale (Basis-60-)Zahlen, nach dem Vorbild der Uhrzeitnotation. 12:34:56 wird als 12×3600 + 34×60 + 56 = 45296 geparst:

duration: 12:34:56   # YAML-1.1-Parser: die Ganzzahl 45296

YAML 1.2 entfernte das vollständig — 12:34:56 ist dort nur ein String. Aber solange irgendein Parser in Ihrer Toolchain aus der 1.1-Ära stammt, riskiert jede doppelpunktgetrennte Zahl, die wie eine Zeit aussieht, „verrechnet“ zu werden. Sehen Sie Doppelpunkte und Ziffern, fügen Sie Anführungszeichen hinzu. Keine Ausnahmen.

Anker und Aliase: Der Preis der Bequemlichkeit

YAML-Anker (&) und Aliase (*) lassen Sie Blöcke wiederverwenden, und der Merge-Key (<<) gibt Ihnen so etwas wie Vererbung:

defaults: &defaults
  timeout: 30
  retries: 3

production:
  <<: *defaults
  timeout: 60

Das ist in Docker Compose und CI-Konfigurationen wirklich nützlich, hat aber drei Haken. Erstens ist ein Alias eine Referenz, keine Kopie — je nach Parser kann das Mutieren eines Vorkommens alle mutieren. Zweitens ist der Merge-Key << eine Erweiterung aus der 1.1-Ära statt Kern-Spezifikation, und die Unterstützung variiert über Sprachbibliotheken. Drittens und am gefährlichsten: die „Billion Laughs“-Alias-Bombe — tief verschachtelte Aliase, die im Speicher exponentiell expandieren, können einen Parsing-Dienst lahmlegen. Begrenzen Sie immer die Alias-Expansion beim Umgang mit nicht vertrauenswürdigem YAML.

Mehrzeilige Strings: | vs >

YAML hat zwei Block-Skalar-Stile mit sehr verschiedenem Verhalten:

literal: |
  line one
  line two
folded: >
  these lines
  get folded

| (literal) behält Zeilenumbrüche — das Ergebnis ist "line one\nline two\n". > (gefaltet) kollabiert Zeilenumbrüche zu Leerzeichen — "these lines get folded\n". Nutzen Sie | für SQL, Shell-Skripte und Zertifikate; nutzen Sie > für lange Prosa-Beschreibungen. Beide nehmen außerdem einen Chomping-Modifikator: | behält einen abschließenden Zeilenumbruch, |- entfernt ihn, und |+ behält alle. Betten Sie ein Skript mit der falschen Variante in eine Kubernetes-ConfigMap ein, und Sie verbringen einen Nachmittag mit dem Debuggen eines Phantom-Zeilenumbruchs.

Tabs sind verboten, Einrückung ist Semantik

YAMLs Regel ist absolut: Einrückung muss aus Leerzeichen bestehen, nie aus Tabs. Ein einzelner verirrter Tab lässt die meisten Parser scheitern, und die Minderheit, die ihn akzeptiert, produziert unergründliche Zeilennummern. Schlimmer: Einrückung ist die Struktur — zwei zusätzliche Leerzeichen, und ein Schlüssel rutscht still in die Verschachtelungsebene des Elternteils, während die Datei noch „in Ordnung aussieht“:

server:
  host: example.com
 port: 8080   # ein Leerzeichen zu wenig: port ist nun ein Top-Level-Schlüssel

Diese Fehler sind mit bloßem Auge fast unsichtbar. Aktivieren Sie „Leerraum anzeigen“ in Ihrem Editor, einigen Sie sich teamweit auf eine Einrückungsbreite (2 oder 4) und parsen Sie eine Konfiguration nach dem Bearbeiten immer tatsächlich. Die geparste Struktur mit dem JSON-Formatierer anzusehen schlägt jedes Leerzeichenzählen im Editor.

Doppelte Schlüssel: Der letzte gewinnt, still

Weder die JSON- noch die YAML-Spezifikation definiert fest, was doppelte Schlüssel bedeuten, also wählten die meisten Parser die gefährlichste Option: kein Fehler, und der spätere Wert überschreibt still den früheren:

database:
  host: db1.internal
  # … einhundert Zeilen später …
  host: db2.internal   # dieser gewinnt; der erste war nie da

Das beißt am härtesten beim Zusammenführen großer Konfigurationsdateien. Manche modernen Parser (bestimmte Go-Bibliotheken, Pythons ruamel.yaml im Strict-Modus) können bei Duplikaten Fehler werfen — aktivieren Sie das in CI, wenn Sie können. Wenn „ich habe die Config geändert, aber nichts passierte“ zuschlägt, diffen Sie die geparste Struktur vorher und nachher mit JSON Diff; der überschriebene Schlüssel zeigt sich sofort.

Sicherheit: Laden Sie nie ungeprüftes YAML einfach

PyYAMLs frühe API ist berüchtigt: yaml.load() instanziierte standardmäßig beliebige Python-Objekte. Ein bösartiges YAML-Dokument konnte Systembefehle ausführen:

!!python/object/apply:os.system ["cat /etc/passwd"]

Dieses „Deserialisierung ist Codeausführung“-Problem ist nicht Python-spezifisch — Ruby und Java (bestimmte SnakeYAML-Nutzungen) haben ähnliche Geschichten. Die eiserne Regel: Für jedes YAML außerhalb Ihrer Vertrauensgrenze nutzen Sie ausschließlich einen sicheren Loader (yaml.safe_load, SnakeYAMLs SafeConstructor). Sichere Loader bauen nur einfache Datenstrukturen — Strings, Zahlen, Listen, Dicts — und lehnen jeden benutzerdefinierten Typ ab. Dass neuere PyYAML-Versionen Sie nun zwingen, einen Loader explizit zu benennen, sagt Ihnen, wie ernst das Ökosystem das nimmt.

Wann YAML vs. JSON

Sie sind keine Konkurrenten; sie dienen verschiedenen Situationen:

  • Von Menschen geschriebene und gelesene Konfigurationsdateien (CI-Pipelines, Orchestrierung, App-Einstellungen): YAML. Kommentare, mehrzeilige Strings und Anker verdienen sich hier ihren Platz.
  • Zwischen Maschinen übertragene Daten (APIs, Message Queues): JSON. Strikte Typregeln, schnelles Parsen, keine impliziten Konvertierungsüberraschungen und ausgereifte Bibliotheken überall.
  • Kommentare gewünscht, aber JSON-ähnliche Strenge nötig: Schauen Sie sich JSON5- oder JSONC-Varianten an, statt YAML in die falsche Aufgabe zu zwingen.

Für Konvertierung und Debugging wechselt der YAML-zu-JSON-Konverter schnell zwischen beiden und legt als Bonus jede implizite Typkonvertierung offen — ein no, das false wurde, ist unmöglich zu übersehen, sobald es JSON ist.

Eine defensive Validierungscheckliste

Ein praktischer Satz Abhilfen zum Abschluss:

  1. Quotieren Sie mehrdeutige Skalare: Alles, was als Boolescher Wert, Zahl oder Zeitstempel vermutet werden könnte (no, 1.10, 12:30, 2024-01-01), kommt in "...".
  2. Nur sichere Loader: Nicht vertrauenswürdige Eingaben gehen immer durch safe_load, mit Limits für Alias-Expansion.
  3. Schema-Validierung: Das Kubernetes-Ökosystem hat kubeconform; für allgemeinen Gebrauch konvertieren Sie YAML zu JSON und validieren mit JSON Schema. Das in CI laufen zu lassen ist weit billiger als Debuggen in der Produktion.
  4. Strict Mode: Kann Ihr Parser bei doppelten Schlüsseln Fehler werfen, aktivieren Sie es.
  5. Nach jeder manuellen Bearbeitung parsen: Bevor Sie handbearbeitetes YAML committen, laden Sie es und vergleichen Sie die Struktur — prüfen Sie die Hierarchie mit dem JSON-Formatierer und die Änderungen mit JSON Diff.

YAMLs Kernspannung ist diese: Um das Schreiben für Menschen angenehm zu machen, schiebt es enorme Interpretationsarbeit auf die Maschine. Verstehen Sie implizite Typisierung, Alias-Expansion und unsichere Loader, und Sie können YAMLs Bequemlichkeit genießen, ohne je von ihr überfallen zu werden.