Dieser Artikel wurde maschinell übersetzt.
Security Briefs
Denial-Of-Service-Angriffe und Schutzmaßnahmen in XML
Bryan Sullivan
DOS-Angriffe (DoS) gehören zu den ältesten Typen von Angriffen gegen Websites. Dokumentierte DOS-Angriffe vorhanden mindestens Rückseite soweit 1992, die SQL-Injektion (in 1998 ermittelt), ist ein Vorläufer Cross-Site scripting (JavaScript war nicht erst 1995 erfunden), und Cross-Site Anforderung Fälschung (CSRF Angriffe erfordern im Allgemeinen Sitzungscookies und Cookies bis 1994 eingeführt wurden nicht).
Von Anfang DoS-Angriffen wurden bei der Hacker Community äußerst beliebt, und es ist leicht zu verstehen, warum. Ein einzelne “ script Kiddie ” Angreifer mit einer minimalen Menge an Fertigkeiten und Ressourcen konnte eine Flut von TCP-SYN-(für synchronisieren) Anforderungen ausreichen, um eine Website außerhalb des Dienstes Entwurzeln generiert werden. Für die fledgling e-Commerce-Welt war dies verheerende: Wenn Benutzer auf eine Website konnte nicht angezeigt wird, konnte nicht Sie Money gibt es sehr gut entweder verbringen. DOS-Angriffe waren das virtuelle Äquivalent der erecting eine Razor-Draht um einen Informationsspeicher Ziegel und erzielten Zaun, mit der Ausnahme, dass alle Informationsspeicher bei einem beliebigen Zeit, Tag oder Nacht angegriffen werden konnte.
Im Laufe der Jahre haben SYN-Flood-Angriffe zum größten Teil durch Verbesserungen in Web-Software und Netzwerk Serverhardware verringert wurde. Allerdings kürzlich wurde ein Resurgence in DOS-Angriffe innerhalb der Sicherheits-Community von Interesse – nicht für “ alten Schule ” auf Netzwerkebene DoS, sondern für die Anwendungsebene DoS und insbesondere für XML-Parser DoS.
XML-DOS-Angriffe sind äußerst asymmetrische: Um die Nutzlast Angriff zu übermitteln, muss ein Angreifer nur einen Bruchteil der Verarbeitungsleistung oder Bandbreite, die das Opfer verbringen, behandeln die Nutzlast verbringen. Schlimmer noch, sind DoS-Sicherheitsrisiken in Code, der XML-verarbeitet auch sehr weit verbreitet. Selbst wenn Sie gründlich getestete Parser wie in Microsoft .NET Framework System.XML-Klassen verwenden, kann der Code immer noch anfällig, es sei denn, Sie explizite Schritte zu schützen.
Dieser Artikel beschreibt einige der neuen XML-DoS-Attacken. Es zeigt außerdem Möglichkeiten zum Erkennen von möglichen DoS-Sicherheitslücken und wie diese in Ihrem Code zu verringern.
XML-Bombs
Ein besonders hartnäckige XML-DoS-Angriff ist die XML-Bombe – einen Block von XML ist wohlgeformt und gültig gemäß den Regeln eines XML-Schemas, aber die abstürzt oder hängt ein Programm auf, wenn das Programm versucht, ihn zu analysieren. Das best-known Beispiel für eine XML-Bombe ist wahrscheinlich der Angriff Exponential Entity-Erweiterung.
Innerhalb eines XML-Dokumenttypdefinition (DTD) können Sie Ihre eigenen Entitäten definieren, die im Wesentlichen als Zeichenfolge Ersetzung Makros dienen. Sie könnten z. B. dieser Zeile hinzufügen, Ihr DTD um alle Vorkommen der Zeichenfolge zu ersetzen &companyname; mit “ Contoso Inc. ”:
<!ENTITY companyname "Contoso Inc.">
Sie können auch schachteln, Entitäten, wie folgt:
<!ENTITY companyname "Contoso Inc.">
<!ENTITY divisionname "&companyname; Web Products Division">
Während die meisten Entwickler mit der Verwendung der externer DTD-Dateien vertraut sind, ist es auch möglich, um Inline-DTDs zusammen mit den XML-Daten einzuschließen. Definieren Sie einfach die DTD direkt in den <! DOCTYPE > Deklaration anstelle von <! DOCTYPE > zum Verweisen auf eine externe DTD-Datei:
<?xml version="1.0"?>
<!DOCTYPE employees [
<!ELEMENT employees (employee)*>
<!ELEMENT employee (#PCDATA)>
<!ENTITY companyname "Contoso Inc.">
<!ENTITY divisionname "&companyname; Web Products Division">
]>
<employees>
<employee>Glenn P, &divisionname;</employee>
<employee>Dave L, &divisionname;</employee>
</employees>
Ein Angreifer kann nun diese drei Eigenschaften von XML (Ersetzung Entitäten, geschachtelte Entitäten und Inline DTDs) eine böswillige XML-Bombe gestalten nutzen. Der Angreifer schreibt ein XML-Dokument mit geschachtelte Entitäten wie im vorherigen Beispiel, aber statt nur eine Ebene tief, He schachtelt die Schachtelung von seinem Entitäten viele wie hier gezeigt tief Ebenen:
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!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;">
]>
<lolz>&lol9;</lolz>
Es sollte beachtet werden, dass dieses XML wohlgeformt und gültig gemäß den Regeln der DTD ist. Wenn ein XML-Parser in diesem Dokument lädt, es erkennt, dass es sich um ein Stammelement “ Lolz ” enthält, die den Text enthält “ &lol9; ”. Allerdings “ &lol9; ” ist eine definierte Einheit, die auf eine Zeichenfolge mit zehn erweitert “ &lol8; ” Zeichenfolgen. Jede “ &lol8; ” Zeichenfolge ist eine definierte Einheit, die auf zehn erweitert “ &lol7; ” Zeichenfolgen und So weiter. Nachdem alle Entität Erweiterungen verarbeitet wurden, enthält dieser kleinen (< 1 KB)-Block des XML-tatsächlich eine Milliarde “ Lol ” s, fast 3 GB Arbeitsspeicher belegen mehr! Sie können diesem Angriff (manchmal auch als den Milliarden Laughs Angriff bezeichnet) für sich selbst mit diesen einfachen Codeblock versuchen – nur bereiten Sie sich, Ihre Test app Prozess dem Task-Manager beenden:
void processXml(string xml)
{
System.Xml.XmlDocument document = new XmlDocument();
document.LoadXml(xml);
}
Einige mehr undurchsichtige Leser vielleicht zu diesem Zeitpunkt, ob es möglich ist, erstellen ein unendlich recursing Entitätserweiterung bestehend aus zwei Entitäten, die aufeinander verweisen:
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol1 "&lol2;">
<!ENTITY lol2 "&lol1;">
]>
<lolz>&lol1;</lolz>
Dies wäre eine sehr effektive Angriff, aber glücklicherweise ist nicht legal XML und wird nicht analysiert werden. Jedoch ist eine andere Variante der die Erweiterung XML Exponential Entity-Bombe, die funktioniert der Angriff quadratische Abbildung, die von Amit Klein von Trusteer Hinweis auf ein erkannt. Statt mehrere kleine, tief geschachtelte Entitäten zu definieren, der Angreifer eine sehr große Entität definiert und bezieht sich auf es oft:
<?xml version="1.0"?>
<!DOCTYPE kaboom [
<!ENTITY a "aaaaaaaaaaaaaaaaaa...">
]>
<kaboom>&a;&a;&a;&a;&a;&a;&a;&a;&a;...</kaboom>
Wenn ein Angreifer die Entität definiert “ &a; ” als 50.000 Zeichen lange und bezieht sich auf, dass Entität 50.000 Mal klicken Sie innerhalb des Stammelements “ neu ” er mit einer XML-Bomb-Angriff Nutzlast etwas über 200 KB Größe endet einrichten, die auf 2,5 GB Wenn analysiert erweitert wird. Dieses Verhältnis Erweiterung ist nicht ganz wie beeindruckenden als mit der Angriff Exponential Entity-Erweiterung, aber es ist immer noch genug, um nach unten der Analyseprozess in Anspruch nehmen.
Eine andere der Klein des XML-Bombe Erfindungen ist der Attribut-Abbildung-Angriff. Viele ältere XML-Parser, einschließlich der in die Runtime von .NET Framework, Version 1.0 und 1.1, XML-Attributen in ein äußerst ineffizient quadratische O (n 2 ) zu analysieren. Erstellen Sie ein XML-Dokument mit einer großen Anzahl von Attributen (z. B. 100.000 oder mehr) für ein einzelnes Element, wird der XML-Parser monopolisiert den Prozessor für einen längeren Zeitraum und deshalb eine Dienstverweigerung verursachen. Allerdings wurde diese Sicherheitsanfälligkeit feste in .NET Framework-Versionen 2.0 und höher.
Externe Entität Angriffe
Statt Ersatzzeichenfolgen Entität als Konstanten zu definieren, ist es auch möglich, diese zu definieren, so dass deren Werte aus externen URIs abgerufen werden:
<!ENTITY stockprice SYSTEM "https://www.contoso.com/currentstockprice.ashx">
Während das genaue Verhalten der jeweiligen Implementierung des XML-Parser abhängt, ist hier die Absicht, dass jedes Mal, wenn der XML-Parser die Entität “ &stockprice; ” erkennt der Parser eine Anforderung zum www.contoso.com/currentstockprice.ashx und Ersetzen Sie die Antwort von dieser Anforderung für die Entität Stockprice erhalten. Dies ist zweifellos ein interessantes und nützliches Feature von XML, aber es ermöglicht außerdem einige undurchsichtige DOS-Angriffe.
Die einfachste Möglichkeit, die externe Entität Funktionalität missbrauchen ist den XML-Parser an eine Ressource senden, die nie zurückgegeben wird; d. h., zum Senden von es in eine unendliche Schleife warten. Beispielsweise wenn ein Angreifer den Server adatum.com gesteuert, könnte er eine generische HTTP-Handler-Datei am http://adatum.com/dos.ashx wie folgt einrichten:
using System;
using System.Web;
using System.Threading;
public class DoS : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
Thread.Sleep(Timeout.Infinite);
}
public bool IsReusable { get { return false; } }
}
Er könnte eine böswillige Einheit, die auf http://adatum.com/dos.ashx verweisen dann erstellen und wenn der XML-Parser die XML-Datei liest, der Parser legen würde. Dies ist jedoch kein besonders effektiv Angriff. Ein DoS-Angriff darum Ressourcen belegen, so dass Sie für legitime Benutzer der Anwendung nicht verfügbar sind. Unsere früheren Beispielen Exponential Entity-Erweiterung und quadratische Abbildung XML Bombs verursacht den Server so, dass große Mengen an Speicher und CPU-Zeit verwendet, in diesem Beispiel wird jedoch nicht. Dieser Angriff wirklich nutzt lediglich einen einzigen Ausführungsthread. Let’s verbessern dieser Angriff (aus Perspektive des Angreifers) durch den Server für einige Ressourcen verbrauchen erzwingen:
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
byte[] data = new byte[1000000];
for (int i = 0; i < data.Length; i++) { data[i] = (byte)’A’; }
while (true)
{
context.Response.OutputStream.Write(data, 0, data.Length);
context.Response.Flush();
}
}
Dieser Code wird eine unendliche Anzahl von schreiben ‘ A ’ Zeichen (jeweils einer Million), die der Antwort Streamen und Kosten einrichten eine riesige Menge an Arbeitsspeicher in einer sehr kurzen Zeitspanne. Wenn der Angreifer oder kann nicht um eine Seite mit seinen einzurichten ist für diesen Zweck besitzen – vielleicht er keine Spur von Beweisen verlassen möchten, die auf ihn zeigt – er kann die externe Entität stattdessen zeigen Sie auf eine sehr große Ressource auf einer Fremdanbieter-Website. Downloads von Film oder die Datei kann für diesen Zweck besonders effektiv; z. B. der Visual Studio 2010 Professional Beta Download mehr als 2 GB ist.
Andere intelligente Variante dieses Angriffs ist noch eine externe Entität auf ein Ziel des Servers Intranetressourcen zeigen. Ermittlung dieser Angriff Technik ist auf Steve Orrin von Intel gutgeschrieben. Diese Technik ist erforderlich, dass der Angreifer damit interne Kenntnisse der Intranet-Sites zugegriffen werden vom Server kann, wenn ein schwerwiegender Angriff Ressource Intranet ausgeführt werden kann, aber insbesondere geeignet, da der Server, seine eigenen Ressourcen (Prozessorzeit, Bandbreite und Arbeitsspeicher) verbringt, um sich selbst oder seine gleichgeordneten Server im selben Netzwerk anzugreifen.
Verteidigen gegen XML-Bombs
Die einfachste Möglichkeit zur Verteidigung gegen alle Arten von XML-Entität Angriffen besteht darin, ganz einfach die Verwendung von Inline-DTD-Schemas in XML-Analyse-Objekten deaktivieren. Dies ist eine einfache Anwendung für das Prinzip der Reduzierung der Angriffsfläche: Wenn Sie ein Feature nicht verwenden, deaktivieren Sie damit Angreifer es leicht missbraucht werden können.
In .NET Framework-Versionen wird durch die booleschen ProhibitDtd-Eigenschaft, die in den Klassen System.Xml.XmlTextReader und System.Xml.XmlReaderSettings gefunden 3.5 und früher, DTD Analyseverhalten gesteuert. Legen Sie diesen Wert auf true, wenn deaktivieren Inline DTDs vollständig:
XmlTextReader reader = new XmlTextReader(stream);
reader.ProhibitDtd = true;
Oder
XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = true;
XmlReader reader = XmlReader.Create(stream, settings);
Der Standardwert von ProhibitDtd in "XmlReaderSettings" true ist, aber der Standardwert von ProhibitDtd in XmlTextReader ist false, was bedeutet, dass Sie explizit auf true, wenn deaktivieren Inline DTDs festgelegt haben.
In .NET Framework, Version 4.0 (in Beta zum Zeitpunkt des Verfassens dieses Artikels) ist die DTD Analyseverhalten geändert worden. Die ProhibitDtd-Eigenschaft wurde zugunsten der neuen DtdProcessing-Eigenschaft verworfen. Sie können diese Eigenschaft festlegen, um nicht zulassen (Standardwert), damit die Common Language Runtime eine Ausnahme ausgelöst werden soll, wenn ein <! DOCTYPE >-Element in der XML-Datei vorhanden ist:
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
XmlReader reader = XmlReader.Create(stream, settings);
Alternativ können Sie die DtdProcessing-Eigenschaft festlegen, zu ignorieren, die nicht auf auftreten eine Ausnahme ausgelöst wird, ein <! DOCTYPE > Element aber wird einfach überspringen es, das nicht verarbeitet werden kann. Schließlich können Sie analysieren DtdProcessing festlegen, wenn Sie zulassen und Inline-DTDs verarbeiten möchten.
Wenn Sie tatsächlich DTDs analysieren möchten, sollten Sie einige zusätzliche Schritte um Ihren Code zu schützen ausführen. Die erste Schritt besteht darin, die Größe der erweiterten Entitäten zu begrenzen. Denken Sie daran, dass die Angriffe, die ich erörtert habe, arbeiten durch das Erstellen von Entitäten, die in riesige Zeichenfolgen zu erweitern und den Parser mit, dass viel Arbeitsspeicher beanspruchen erzwingen. Die MaxCharactersFromEntities-Eigenschaft des Objekts "XmlReaderSettings" festlegen, können Sie die Anzahl der Zeichen cap, die über Erweiterungen Entität erstellt werden können. Bestimmen Sie der angemessenen bis, und legen Sie die Eigenschaft entsprechend fest. Hier ist ein Beispiel:
XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.MaxCharactersFromEntities = 1024;
XmlReader reader = XmlReader.Create(stream, settings);
Verteidigen gegen externe Entität Angriffe
Zu diesem Zeitpunkt haben wir diesen Code abgesichert, so dass es viel weniger anfällig für XML-Bombs ist, aber wir noch nicht noch die Gefahren mildern böswillige externe Entitäten behandelt. Sie können Ihre Ausfallsicherheit gegen diese Angriffe verbessern, wenn Sie das Verhalten von XmlReader, Anpassen indem Sie seine XmlResolver ändern. XmlResolver-Objekte werden zum Auflösen externer Verweise, einschließlich externe Entitäten verwendet. XmlTextReader-Instanzen, ebenso wie XmlReader.Create, den Aufrufen zurückgegebenen XmlReader-Instanzen werden mit Standard (tatsächlich XmlUrlResolvers) XmlResolvers vorausgefüllt. Sie können verhindern, dass XmlReader Auflösen von externe Entitäten und dennoch die Möglichkeit, um Inline-Entitäten zu beheben, indem Sie XmlResolver-Eigenschaft die "XmlReaderSettings" auf null setzen. Dies ist die Reduzierung der Angriffsfläche bei der Arbeit erneut, wenn Sie die Funktion nicht benötigen, schalten Sie ihn aus:
XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.MaxCharactersFromEntities = 1024;
settings.XmlResolver = null;
XmlReader reader = XmlReader.Create(stream, settings);
Wenn diese Situation für Sie zutrifft, wenn Sie wirklich, wirklich externe Entitäten auflösen müssen – alle Hoffnung ist nicht verloren, aber Sie haben ein wenig mehr Arbeit tun. Um XmlResolver widerstandsfähiger für Denial-of-Service-Angriffe zu machen, müssen Sie das Verhalten auf drei Arten ändern. Zunächst müssen Sie ein Anforderungstimeout zur Verhinderung von Angriffen unendliche Verzögerung festlegen. Zweitens müssen Sie die Datenmenge beschränken, die abgerufen werden. Schließlich ein Measure in Tiefenverteidigung müssen Sie verhindern, dass den XmlResolver Abrufen von Ressourcen auf lokalen Host. All dies erreichen, indem Sie eine benutzerdefinierte XmlResolver-Klasse erstellen.
Die Methode XmlResolver GetEntity unterliegt das Verhalten, das Sie ändern möchten. Erstellen Sie eine neue Klasse, die XmlUrlResolver XmlSafeResolver abgeleitet, und überschreiben Sie die GetEntity-Methode wie folgt:
class XmlSafeResolver : XmlUrlResolver
{
public override object GetEntity(Uri absoluteUri, string role,
Type ofObjectToReturn)
{
}
}
Das Standardverhalten der XmlUrlResolver.GetEntity-Methode sieht wie der folgende Code, die Sie als Ausgangspunkt für Ihre Implementierung verwenden können:
public override object GetEntity(Uri absoluteUri, string role,
Type ofObjectToReturn)
{
System.Net.WebRequest request = WebRequest.Create(absoluteUri);
System.Net.WebResponse response = request.GetResponse();
return response.GetResponseStream();
}
Die erste Änderung ist Timeoutwerte anwenden, wenn die Anforderung vornehmen und beim Lesen der Antwort. Die System.NET.WebRequest sowohl der System.IO.Stream-Klassen bieten inhärenten Unterstützung für Timeouts. Im Beispielcode in Abbildung 1 gezeigte ich einfach den Timeoutwert hartcodieren, aber Sie können einfach aussetzen eine öffentliche Timeout-Eigenschaft für die XmlSafeResolver-Klasse auf Wunsch größer Konfigurierbarkeit.
Abbildung 1 Konfigurieren des Timeout-Werte
private const int TIMEOUT = 10000; // 10 seconds
public override object GetEntity(Uri absoluteUri, string role,
Type ofObjectToReturn)
{
System.Net.WebRequest request = WebRequest.Create(absoluteUri);
request.Timeout = TIMEOUT;
System.Net.WebResponse response = request.GetResponse();
if (response == null)
throw new XmlException("Could not resolve external entity");
Stream responseStream = response.GetResponseStream();
if (responseStream == null)
throw new XmlException("Could not resolve external entity");
responseStream.ReadTimeout = TIMEOUT;
return responseStream;
}
Die nächste Schritt ist die maximale Datenmenge cap, die in der Antwort abgerufen wird. Es gibt keine “ MaxSize ”-Eigenschaft oder die Entsprechung für die Stream-Klasse, so dass Sie diese Funktionalität nicht selbst implementieren. Zu diesem Zweck können Sie zu einem Zeitpunkt Daten aus einem Teil der Antwort-Stream gelesen und in einen Stream lokalen Zwischenspeicher zu kopieren. Wenn die Gesamtzahl der aus dem Antwortstream des gelesenen Bytes einen vordefinierten Grenzwert (erneut hartcodiert der Einfachheit halber nur) überschreitet, beenden Sie beim Lesen aus dem Stream und eine Ausnahme (siehe Abbildung 2 ).
Abbildung 2 beschränken Sie die maximale Anzahl von Minuten abgefragte Daten
private const int TIMEOUT = 10000; // 10 seconds
private const int BUFFER_SIZE = 1024; // 1 KB
private const int MAX_RESPONSE_SIZE = 1024 * 1024; // 1 MB
public override object GetEntity(Uri absoluteUri, string role,
Type ofObjectToReturn)
{
System.Net.WebRequest request = WebRequest.Create(absoluteUri);
request.Timeout = TIMEOUT;
System.Net.WebResponse response = request.GetResponse();
if (response == null)
throw new XmlException("Could not resolve external entity");
Stream responseStream = response.GetResponseStream();
if (responseStream == null)
throw new XmlException("Could not resolve external entity");
responseStream.ReadTimeout = TIMEOUT;
MemoryStream copyStream = new MemoryStream();
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = 0;
int totalBytesRead = 0;
do
{
bytesRead = responseStream.Read(buffer, 0, buffer.Length);
totalBytesRead += bytesRead;
if (totalBytesRead > MAX_RESPONSE_SIZE)
throw new XmlException("Could not resolve external entity");
copyStream.Write(buffer, 0, bytesRead);
} while (bytesRead > 0);
copyStream.Seek(0, SeekOrigin.Begin);
return copyStream;
}
Als Alternative können Sie umbrochen Stream-Klasse und das Limit der überschriebenen Read-Methode direkt einchecken implementieren (siehe Abbildung 3 ). Dies ist eine effizientere Implementierung, da Sie den zusätzlichen Arbeitsspeicher für die zwischengespeicherten MemoryStream in dem früheren Beispiel reserviert speichern.
Abbildung 3 definieren Sie eine Größe von-Stream-Wrapperklasse eingeschränkt
class LimitedStream : Stream
{
private Stream stream = null;
private int limit = 0;
private int totalBytesRead = 0;
public LimitedStream(Stream stream, int limit)
{
this.stream = stream;
this.limit = limit;
}
public override int Read(byte[] buffer, int offset, int count)
{
int bytesRead = this.stream.Read(buffer, offset, count);
checked { this.totalBytesRead += bytesRead; }
if (this.totalBytesRead > this.limit)
throw new IOException("Limit exceeded");
return bytesRead;
}
...
}
Nun einfach Wrappen von WebResponse.GetResponseStream in einem LimitedStream zurückgegebenen Stream und der LimitedStream zurückzugeben, von der GetEntity-Methode (siehe Abbildung 4 ).
Abbildung 4 mithilfe von LimitedStream in GetEntity
private const int TIMEOUT = 10000; // 10 seconds
private const int MAX_RESPONSE_SIZE = 1024 * 1024; // 1 MB
public override object GetEntity(Uri absoluteUri, string role, Type
ofObjectToReturn)
{
System.Net.WebRequest request = WebRequest.Create(absoluteUri);
request.Timeout = TIMEOUT;
System.Net.WebResponse response = request.GetResponse();
if (response == null)
throw new XmlException("Could not resolve external entity");
Stream responseStream = response.GetResponseStream();
if (responseStream == null)
throw new XmlException("Could not resolve external entity");
responseStream.ReadTimeout = TIMEOUT;
return new LimitedStream(responseStream, MAX_RESPONSE_SIZE);
}
Fügen Sie abschließend ein weitere Tiefenverteidigung in Measure durch das Blockieren der Entität Auflösung des URIs, die in der lokalen Host (siehe Abbildung 5 ) wurden.diese auflösen URIs beginnend mit http://localhost, http://127.0.0.1 und file:// URIs enthält. Beachten Sie, dass dies eine Sicherheitsanfälligkeit bezüglich der Offenlegung von sehr hartnäckige Informationen außerdem in der Angreifer gestalten können Entitäten auf file://resources verhindert, den Inhalt von denen dann ordnungsgemäß abgerufen und in das XML-Dokument vom Parser geschrieben.
Abbildung 5 Blockieren lokaler Host Entity Resolution
public override object GetEntity(Uri absoluteUri, string role,
Type ofObjectToReturn)
{
if (absoluteUri.IsLoopback)
return null;
...
}
Nachdem Sie eine sicherere XmlResolver definiert haben, müssen Sie es XmlReader zuweisen. Explizit instanziiert ein XmlReaderSettings-Objekt, legen Sie die XmlResolver-Eigenschaft auf eine Instanz der XmlSafeResolver und verwenden Sie anschließend die XmlReaderSettings beim Erstellen von XmlReader, wie hier gezeigt:
XmlReaderSettings settings = new XmlReaderSettings();
settings.XmlResolver = new XmlSafeResolver();
settings.ProhibitDtd = false; // comment out if .NET 4.0 or later
settings.DtdProcessing = DtdProcessing.Parse; // comment out if
// .NET 3.5 or earlier
settings.MaxCharactersFromEntities = 1024;
XmlReader reader = XmlReader.Create(stream, settings);
Weitere Überlegungen
Es ist wichtig, die in vielen der System.XML-Klassen, beachten Sie, wenn XmlReader nicht explizit auf ein Objekt oder eine Methode bereitgestellt wird und dann eine implizit im Frameworkcode erstellt wird. Diese implizit erstellte XmlReader keinen keines der zusätzlichen Verteidigungsmaßnahmen in diesem Artikel angegeben, und es werden anfällig für Angriffe. Der erste Codeausschnitt in diesem Artikel ist ein gutes Beispiel für dieses Verhalten:
void processXml(string xml)
{
System.Xml.XmlDocument document = new XmlDocument();
document.LoadXml(xml);
}
Dieser Code ist vollständig alle in diesem Artikel beschriebenen Angriffe anfällig. Um diesen Code zu verbessern, explizit erstellen Sie einen XmlReader mit entsprechenden Einstellungen (entweder deaktivieren Inline-DTD analysieren, oder geben Sie eine sicherere Resolver-Klasse) und verwenden Sie die Überladung XmlDocument.Load(XmlReader) anstelle von XmlDocument.LoadXml oder keines der anderen XmlDocument.Load-Überladungen, wie in Abbildung 6 dargestellt.
Abbildung 6 Anwenden von Einstellungen, um XmlDocument Analyse Safer Entity
void processXml(string xml)
{
MemoryStream stream =
new MemoryStream(Encoding.Default.GetBytes(xml));
XmlReaderSettings settings = new XmlReaderSettings();
// allow entity parsing but do so more safely
settings.ProhibitDtd = false;
settings.MaxCharactersFromEntities = 1024;
settings.XmlResolver = new XmlSafeResolver();
XmlReader reader = XmlReader.Create(stream, settings);
XmlDocument doc = new XmlDocument();
doc.Load(reader);
}
XLinq ist etwas sicherer in den Standardeinstellungen; Analysieren von DTD ist der XmlReader standardmäßig für System.Xml.Linq.XDocument erstellt lässt jedoch automatisch MaxCharactersFromEntities auf 10.000.000 festgelegt und lässt keine externe Entität Auflösung. Wenn Sie explizit einen XmlReader für XDocument bereitzustellen, müssen Sie unbedingt die defensiven weiter oben beschriebenen Einstellungen gelten.
Zusammenfassung
XML-Entitätserweiterung ist ein leistungsstarkes Feature, jedoch können problemlos von einem Angreifer zum Dienst für Ihre Anwendung verweigern missbraucht werden. Stellen Sie sicher, dass das Prinzip der Angriffsflächenverringerung befolgt werden und Entitätserweiterung deaktivieren, wenn Sie deren Verwendung nicht erforderlich ist. Andernfalls, gelten Sie die entsprechenden Verteidigung zum Begrenzen des maximalen Zeit und Arbeitsspeicher die Anwendung verbringen kann darauf.
Bryan Sullivan ist eine Security Programmmanager für das Microsoft Security Development Lifecycle-Team, Sicherheitsprobleme für Webanwendung und .NET spezialisiert. Er ist Autor von “ AJAXSecurity ” (Addison-Wesley, 2007).