Ein Billion-Laughs-Angriff ist ein Denial-Of-Service-Angriff mittels präparierten XML-Dokument.
Die Beschreibung hier bezieht sich auf das XML-Format. Betroffen sind aber alle Formate, die eine Art von rekursiver (Makro-)Expansion unterstützen (wie bspw. YAML mittels Anchors und References).
Allgemeines
Ein Denial-Of-Service-Angriff sorgt dafür, daß ein System Resourcen (Speicher, Rechenzeit, etc.) in Übermaß konsumiert und damit nur noch eingeschränkt, langsam oder überhaupt nicht mehr reagiert.
XML-Grundlagen
Entitäten in XML-Dokumenten sind Namen, eingeschlossen in einem führenden Ampersand (&) und einem abschliessenden Semikolon (;). < ist bspw. eine vordefinierte Entität zum Encodieren von < in XML-Inhalten. (Ohne diese Encodierung würde der XML-Parser hier den Start eines öffnenden oder schliessenden XML-Elements erkennen.). Weitere Entitäten sind bspw. auch die dezimalen oder hexadezimalen Darstellungen von Sonderzeichen. So wäre bspw. © (als dezimale Form) bzw. © (als hexadezimale Form) das Copyright-Zeichen (©).
Entitäten können aber auch im XML-Dokument definiert werden:
<!DOCTYPE myDocument [
<!ENTITY foo "bar">
]>
<root>
<text>&foo;</text>
</root>
In diesem Beispiel wird eine XML-Entität namens foo definiert, welcher der Text bar zugewiesen wird. An allen Stellen im XML-Dokument, an denen der Parser &foo; findet wird der Text bar eingetragen. Das ist erstmal kein Problem.
Das Problem
XML erlaubt es jedoch auch XML-Entitäten mit anderen XML-Entitäten zu definieren:
<!DOCTYPE myDocument [
<!ENTITY bar "bar">
<!ENTITY foo "&bar;">
]>
<root>
<text>&foo;</text>
</root>
Hier setzt der Billion-Laughs-Angriff auf. Er erzeugt eine riesige Datenmenge im Speichern des Rechners.
Was passiert bei dem nachfolgenden XML-Dokument?
<!DOCTYPE myDocument [
<!ENTITY lol0 "lol">
<!ENTITY lol1 "&lol0;&lol0;&lol0;&lol0;&lol0;&lol0;&lol0;&lol0;&lol0;&lol0;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<root>
<text>&lol9;</text>
</root>
lol9 wird durch 10x lol8 ersetzt. Jedes lol8 wird durch 10x lol7 ersetzt, jedes davon wiederum durch 10x lol6 usw. Am Ende sind es dann 109 lol0, die durch ein x ersetzt werden. Das ist am Ende ein Text mit 1 Milliarde x!
Lösungen
Es gibt ein paar Lösungen, von denen man auswählen kann:
- Keine XML-Dokumente aus unsicheren Quellen zulassen. Das klingt erstmal sinnvoll, aber es gibt Fälle, in denen genau das erforderlich ist, beispielsweise bei Diensten, die GPX-Daten verarbeiten.
- Keine Expansion von Entitäten erlauben. Damit sollten nur vordefinierte Entitäten expandiert werden, aber keine selbstdefinierten. Dies ist meiner Erfahrung nach die sinnvollste Lösung, wenn XML-Dokumente aus Fremdquellen verarbeitet werden sollen.
- Begrenzung der Anzahl der Expansionen. Damit kann festgelegt werden, wieviele Expansionen durchgeführt werden können, bevor der Parser abbricht. Nicht jeder XML-Parser unterstützt dies und Unterschiede zwischen den XML-Parsern sind mögllich. (z.B. Begrenzung der Anzahl aller Expansionen im gesamten Dokument ⇔ Begrenzung der Expansionen pro gefundener Entität im Dokument)