Condividi tramite


Il presente articolo è stato tradotto automaticamente.

Informazioni di protezione

Attacchi e difese di tipo Denial Of Service (DOS) in XML

Bryan Sullivan

Gli attacchi di tipo Denial of service (DoS) sono tra i tipi di attacchi contro siti Web meno recenti. Intersito documentata DoS attacchi esistano almeno posteriore quanto 1992, predates SQL injection (scoperti nel 1998), script (JavaScript non è stato inventato fino 1995) e intersito contraffazione richiesta (CSRF attacchi richiedono in genere i cookie di sessione e cookie non sono state introdotte fino al 1994).

Dall'inizio, gli attacchi DoS sono stati diffusi altamente con la comunità di hacker ed è facile da comprendere il motivo. Un aggressore “ script kiddie ” singola con una quantità minima di competenze e risorse in grado di generare un'enorme quantità di richieste SYN TCP (per la sincronizzazione) sufficienti Battente un sito di servizio. Per tutto il mondo e-commerce fledgling era devastante: Se è Impossibile ottenere gli utenti a un sito, essi Impossibile dedicare molto bene denaro non vi sia. Gli attacchi doS sono stati l'equivalente virtuale di erecting un cavo razor fence intorno a un archivio di mattoni e deteriorati, ad eccezione del fatto che qualsiasi archivio può essere attaccato in qualsiasi momento.

Nel corso degli anni, attacchi SYN flood sono stati attenuati in gran parte da miglioramenti in hardware e software di rete del server Web. Tuttavia, Ultimamente si è verificato un resurgence di interesse in attacchi DoS all'interno della comunità di protezione, ovvero non per “ vecchio scuola ” a livello di rete DoS, bensì per DoS a livello di applicazione e in particolare per il parser XML DoS.

Gli attacchi XML DoS sono estremamente asimmetrici: Per distribuire il payload di attacco, un utente malintenzionato deve dedicare solo una frazione della potenza di elaborazione o larghezza di banda della vittima debba spendere per gestire il payload. Peggio ancora, le vulnerabilità di DoS in codice che elabora il XML sono inoltre estremamente diffusione. Anche se si stanno utilizzando i parser accuratamente testati simili a quelli trovati nelle classi System.XML di Microsoft .NET Framework, il codice può risultare ancora esposto a meno che non si esegua passaggi espliciti per proteggerli.

In questo articolo vengono descritti alcuni nuovi attacchi XML DoS. Vengono inoltre illustrati modi per rilevare potenziali vulnerabilità di DoS e come attenuare li nel codice.

XML bombe

Un tipo di attacco XML DoS particolarmente rischiose è bomb XML, ovvero un blocco di XML che è ben formato e valido in base alle regole di uno schema XML, ma che si blocca o si blocca un programma quando tale programma tenta di analizzarlo. L'esempio best-known di un bomb XML è probabilmente l'attacco esponenziale espansione di entità.

All'interno di una XML document type definition (DTD), è possibile definire la propria entità, fungono essenzialmente da macro per la sostituzione di stringa. Ad esempio, è possibile aggiungere questa riga per la DTD per sostituire tutte le occorrenze della stringa &companyname; con “ Contoso Inc. ”:

<!ENTITY companyname "Contoso Inc.">

È inoltre possibile nidificare le entità, simile al seguente:

<!ENTITY companyname "Contoso Inc.">
<!ENTITY divisionname "&companyname; Web Products Division">

Mentre la maggior parte degli sviluppatori si ha familiarità con l'utilizzo dei file DTD esterni, è inoltre possibile includere DTD inline unitamente ai dati XML stesso. Sufficiente definire la DTD in direttamente il <! DOCTYPE > dichiarazione invece di utilizzare <! DOCTYPE > per fare riferimento a un file DTD esterno:

<?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>

Un utente malintenzionato può ora usufruire di queste tre proprietà di XML (le entità di sostituzione, entità nidificate e DTD inline) predisporre un bomb XML dannoso. L'utente malintenzionato scrive un documento XML con entità nidificate esattamente come nell'esempio precedente, ma invece di nidificazione di un solo livello fondo, nidifica ha il suo entità molti livelli di profondità, come illustrato di seguito:

<?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>

Notare che questo file XML sia ben formato e valido in base alle regole della definizione DTD. Quando un parser XML viene caricato in questo documento, vede che include un elemento principale “ lolz ”, che contiene il testo “ &lol9; ”. Tuttavia, “ &lol9; ” è un'entità definita che espande a una stringa contenente fino a dieci volte “ &lol8; ” stringhe. Ogni “ &lol8; ” stringa è un'entità definita espande a dieci “ &lol7; ” stringhe e così via. Dopo l'elaborazione di tutte le espansioni delle entità, questo piccolo blocco di (< 1 KB) di XML contengono effettivamente un miliardo “ lol ” s, occupare quasi 3 GB di memoria!  È possibile provare a questo tipo di attacco (detto anche l'attacco laughs miliardi) per se stessi utilizzando questo blocco di codice molto semplice, ovvero solo essere preparati a interrompere il processo di applicazione test da Task Manager:

void processXml(string xml)
{
    System.Xml.XmlDocument document = new XmlDocument();
    document.LoadXml(xml);
}

Alcuni dei lettori più devious potrebbe chiedendo a questo punto se è possibile creare un'espansione di entità all'infinito recursing costituito da due entità che fanno riferimento a altra:

<?xml version="1.0"?>
<!DOCTYPE lolz [
  <!ENTITY lol1 "&lol2;">
  <!ENTITY lol2 "&lol1;">
]>
<lolz>&lol1;</lolz>

Questo sarebbe un attacco molto efficacia, ma Fortunatamente non è legale XML e non eseguirà l'analisi. Tuttavia, un'altra variante della bomb esponenziale Entity Expansion XML funziona è l'attacco di Blowup Quadratic individuata da Amit Klein di Trusteer. Invece di definire più entità di piccole dimensioni, molto nidificate, l'utente malintenzionato definisce un'entità molto grande e fa riferimento a tale numero di volte:

<?xml version="1.0"?>
<!DOCTYPE kaboom [
  <!ENTITY a "aaaaaaaaaaaaaaaaaa...">
]>
<kaboom>&a;&a;&a;&a;&a;&a;&a;&a;&a;...</kaboom>

Se un utente malintenzionato definisce l'entità “ &a; ” come 50.000 caratteri long e si intende che entità 50.000 volte all'interno dell'elemento di “ boom ” radice, egli finisce con un payload di attacco bomb XML leggermente oltre 200 KB nella dimensione si estende fino a 2,5 GB quando analizzato. Questo rapporto di espansione non è abbastanza come impressionante come con l'attacco esponenziale espansione di entità, ma è comunque sufficiente provoca l'arresto il processo di analisi.

Un altro XML bomb rilevamenti di Klein è attacco Attribute Blowup. Molti meno recenti parser XML, inclusi quelli nel runtime di .NET Framework versioni 1.0 e 1.1, analizzare gli attributi XML in un estremamente inefficiente O quadratica (2 n ). Mediante la creazione di un documento XML con un numero elevato di attributi (ad esempio 100.000 o più) per un singolo elemento, il parser XML verrà monopolizzano il processore per un lungo periodo di tempo e di conseguenza causare una condizione di denial of service. Tuttavia, questa vulnerabilità è stata fisso nelle versioni di .NET Framework 2.0 e versioni successive.

Attacchi esterni Entity

Invece di definire le stringhe di sostituzione entità come costanti, è anche possibile definirli in modo che i relativi valori vengono estratti da URI esterni:

<!ENTITY stockprice SYSTEM    "https://www.contoso.com/currentstockprice.ashx">

Mentre il comportamento esatto dipende dalla particolare implementazione del parser XML, lo scopo qui è che, ogni volta che il parser XML rileva l'entità “ &stockprice; ” il parser verrà eseguire una richiesta per www.contoso.com/currentstockprice.ashx e quindi sostituire la risposta ricevuta da tale richiesta per l'entità stockprice. È indubbiamente una funzionalità utile e interessante di XML, ma consente anche di alcuni attacchi DoS devious.

È il modo più semplice per abusare funzionalità entità esterna per inviare il parser XML a una risorsa non restituirà mai; vale a dire per l'invio in un infinito in attesa ciclo. Ad esempio, se un utente malintenzionato disponesse di controllo di adatum.com server, egli potrebbe impostare un file del gestore HTTP generico in http://adatum.com/dos.ashx come indicato di seguito:

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; } }
}

Egli potrebbe quindi creare un'entità dannosa che puntava http://adatum.com/dos.ashx e quando il parser XML legge il file XML, il parser potrebbe bloccarsi. Tuttavia, ciò non è un attacco particolarmente efficacia. Il punto di un attacco DoS è a consumare le risorse in modo che siano non disponibili per gli utenti legittimi dell'applicazione. Nostri esempi precedenti di bombe esponenziale espansione di entità e XML Blowup Quadratic ha causato il server da utilizzare grandi quantità di memoria e il tempo della CPU, ma in questo esempio non esiste. Tutto questo attacco realmente consuma è un singolo thread di esecuzione. Let’s per migliorare questo tipo di attacco (dal punto di vista dell'utente malintenzionato), imponendo al server per l'utilizzo di alcune risorse:

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();
    }
}

Questo codice verrà scritto un numero infinito di ‘ A ’ flusso di caratteri (un milione alla volta) alla risposta e chew una notevole quantità di memoria in un periodo di tempo molto breve. Se l'utente malintenzionato è impossibile oppure è Impossibile impostare una pagina del suo proprietario per questo scopo, forse egli non desidera di lasciare un itinerario di prova che punta a lui, ovvero entità esterna invece egli può puntare a una risorsa molto grande in un sito Web di terze parti. Download filmato o il file può essere particolarmente efficace per questo scopo, ad esempio, il download della versione beta di Visual Studio 2010 Professional è più di 2 GB.

Ancora un'altra variante intelligente di questo tipo di attacco è punta un'entità esterna a una risorse di rete intranet del server di destinazione. Individuazione di questa tecnica di attacco viene accreditato per Steve Orrin di Intel. Questa tecnica richiede all'utente malintenzionato di essere a conoscenza interno dei siti dell'intranet accessibili dal server, ma se è possibile eseguire un attacco di risorsa di rete intranet, può risultare particolarmente efficacia perché il server è sprecare le proprie risorse (tempo processore, della larghezza di banda e memoria) agli attacchi di se stesso o relativi server di pari livello nella stessa rete.

Come difendersi dai XML bombe

Il modo più semplice per difendersi da tutti i tipi di attacchi di entità XML è semplicemente disattivare del tutto l'utilizzo di schemi DTD inline negli oggetti analisi XML. Si tratta di una semplice applicazione del principio di riduzione della superficie di attacco: Se non si sta utilizzando una funzionalità, disattivarlo in modo che i pirati informatici non saranno in grado di abusare di esso.

Nelle versioni di .NET Framework 3.5 e versioni precedente, comportamento di analisi della DTD è controllato mediante la proprietà ProhibitDtd booleano trovata nelle classi System.Xml.XmlTextReader e System.Xml.XmlReaderSettings. Impostare questo valore su true per disattivare inline DTD completamente:

XmlTextReader reader = new XmlTextReader(stream);
reader.ProhibitDtd = true;

o

XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = true;
XmlReader reader = XmlReader.Create(stream, settings);

Il valore predefinito di ProhibitDtd in XmlReaderSettings è true, ma il valore predefinito di ProhibitDtd in XmlTextReader è false, il che significa che è necessario impostare in modo esplicito per true per disattivare inline DTD.

In .NET Framework versione 4.0 (in versione beta al momento della stesura di questo articolo), DTD comportamento di analisi è stato modificato. La proprietà ProhibitDtd è obsoleta in favore della nuova proprietà DtdProcessing. È possibile impostare questa proprietà su non consentire (valore predefinito) per far sì che il runtime generare un'eccezione se un <! DOCTYPE > elemento è presente nel XML:

XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
XmlReader reader = XmlReader.Create(stream, settings);

In alternativa, è possibile impostare la proprietà DtdProcessing a Ignora, non verrà generata un'eccezione in presenza di un <! DOCTYPE > elemento ma verranno semplicemente ignorate e non elaborare. Infine, è possibile impostare DtdProcessing analisi se si desidera consentire e l'elaborazione DTD inline.

Se davvero si desidera analizzare le definizioni DTD, è necessario completare alcuni passaggi aggiuntivi per proteggere il codice. Il primo passaggio consiste nel limitare le dimensioni di entità espanse. Tenere presente che gli attacchi trattati funzionano mediante la creazione di entità che espandere le stringhe enormi e forzare il parser per consumare grandi quantità di memoria. Impostando la proprietà MaxCharactersFromEntities dell'oggetto XmlReaderSettings, è possibile chiudere il numero di caratteri che possono essere creati tramite espansioni delle entità. Determinare un massimo di ragionevole e impostare la proprietà in modo appropriato. Ecco un esempio:

XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.MaxCharactersFromEntities = 1024;
XmlReader reader = XmlReader.Create(stream, settings);

Come difendersi dagli attacchi esterni Entity

A questo punto, è stato rafforzato questo codice, in modo che è molto meno vulnerabile a bombe XML, ma abbiamo ancora non indirizzati pericoli provocati dagli dannose le entità esterne. Se si personalizza il comportamento della classe XmlReader modificando relativo XmlResolver, è possibile migliorare la capacità di recupero da tali attacchi. Gli oggetti XmlResolver vengono utilizzati per risolvere i riferimenti esterni, tra cui le entità esterne. Istanze XmlTextReader, come pure le istanze di XmlReader restituite dalle chiamate a XmlReader.Create, vengono popolate in precedenza con predefinito XmlResolvers (XmlUrlResolvers effettivamente). È possibile impedire XmlReader di risoluzione entità esterne consentendo comunque per risolvere le entità inline impostando la proprietà XmlResolver di XmlReaderSettings su null. Si tratta di attacco riduzione della superficie al lavoro nuovamente; se la funzionalità non è necessario, disattivarlo:

XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.MaxCharactersFromEntities = 1024;
settings.XmlResolver = null;
XmlReader reader = XmlReader.Create(stream, settings);

Se questa situazione non si applica all'utente, ovvero se è effettivamente, veramente necessario risolvere le entità esterne, ovvero speranza tutte non è andata persa ma è necessario un po' più operazioni da eseguire. Per rendere XmlResolver più resistenti agli attacchi di tipo denial of service, è necessario modificarne il comportamento in tre modi. Innanzitutto, è necessario impostare un timeout della richiesta a impedire gli attacchi di ritardo infinito. In secondo luogo, è necessario limitare la quantità di dati che consente di recuperare. Infine, come misura di difesa in profondità, è necessario limitare il XmlResolver dal recupero di risorse sull'host locale. Tutto questo scopo, creare una classe XmlResolver personalizzata.

Il comportamento che si desidera modificare è regolato dal metodo XmlResolver GetEntity. Creare una nuova classe derivata XmlSafeResolver da XmlUrlResolver ed eseguire l'override del metodo GetEntity come segue:

class XmlSafeResolver : XmlUrlResolver
{
    public override object GetEntity(Uri absoluteUri, string role, 
        Type ofObjectToReturn)
    {

    }
}

Il comportamento predefinito del metodo XmlUrlResolver.GetEntity è simile al codice riportato di seguito, è possibile utilizzare come punto di partenza per l'implementazione seguente:

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();
}

La prima modifica consiste nell'applicare i valori di timeout quando si effettua la richiesta e durante la lettura della risposta. Il System.NET.WebRequest e le classi System.IO.Stream forniscono supporto intrinseco per timeout. Nell'esempio di codice illustrato in di Figura 1, è possibile semplicemente impostare come hardcoded il valore di timeout, ma potrebbe facilmente esporre una proprietà pubblica Timeout sulla classe XmlSafeResolver se si desidera maggiore configurabilità.

Figura 1 valori di Timeout Configuring

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;
}

Il passaggio successivo è per chiudere la quantità massima di dati recuperati nella risposta. È presente alcuna proprietà “ MaxSize ” o l'equivalente per la classe Stream in modo che sia necessario implementare manualmente questa funzionalità. A tale scopo, è possibile leggere i dati della porzione di un flusso di risposta in un momento e copiare in una cache locale del flusso. Se il numero totale di byte letti dal flusso di risposta supera un limite predefinito (nuovamente hardcoded per semplicità solo), interrompere la lettura dal flusso e genera un'eccezione (vedere di Figura 2).

Nella figura 2 Capping la quantità massima di dati recuperati

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;
}

In alternativa, è possibile eseguire il wrapping della classe Stream e implementare il limite di controllo direttamente nel metodo sottoposto a override lettura (vedere di Figura 3). Si tratta di un'implementazione più efficiente poiché salvare memoria aggiuntiva allocata per MemoryStream memorizzati nella cache dell'esempio precedente.

Nella figura 3 definizione di una dimensione-limitata classe Stream Wrapper

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;
    }

    ...
}

A questo punto, semplicemente eseguire il wrapping nel flusso restituito da WebResponse.GetResponseStream in un LimitedStream e restituire il LimitedStream dal metodo GetEntity (vedere di Figura 4).

Nella figura 4 utilizzo 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);
}

Infine, aggiungere una misura di difesa in profondità ulteriori bloccando la risoluzione di entità di URI che consente di risolvere il .questo di host locale (vedere di Figura 5) include gli URI che inizia con http://localhost, http://127.0.0.1 e gli URI file://. Si noti che ciò impedisce inoltre a una vulnerabilità di divulgazione di informazioni molto rischiose in cui gli utenti malintenzionati possono predisporre le entità che fanno riferimento a file://resources, il cui contenuto è quindi duly recuperato e scritto nel documento XML dal parser.

Nella figura 5 Blocking Local Host Entity Resolution

public override object GetEntity(Uri absoluteUri, string role,
    Type ofObjectToReturn)
{
    if (absoluteUri.IsLoopback)
        return null;
    ...
}

È stato definito un XmlResolver più sicuro, è necessario applicare a XmlReader. Creare in modo esplicito un'istanza di un oggetto XmlReaderSettings, impostare la proprietà XmlResolver a un'istanza di XmlSafeResolver e utilizzare quindi il XmlReaderSettings durante la creazione di XmlReader, come illustrato di seguito:

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);

Ulteriori considerazioni

È importante notare che in molte delle classi System.XML, se un XmlReader non viene esplicitamente fornito a un oggetto o a un metodo, quindi uno viene creato in modo implicito per essa nel codice del framework. Questo creato in modo implicito XmlReader non avrà alcuna le difese aggiuntive specificate in questo articolo, e sarà vulnerabile agli attacchi. Il primo frammento di codice in questo articolo è un ottimo esempio di questo comportamento:

void processXml(string xml)
{
    System.Xml.XmlDocument document = new XmlDocument();
    document.LoadXml(xml);
}

Questo codice è completamente esposto a tutti gli attacchi descritti in questo articolo. Per migliorare questo codice, creare un oggetto XmlReader con le impostazioni appropriate (una DTD inline di disattivare l'analisi o specifica una classe di sistema di risoluzione dei conflitti più sicura) in modo esplicito e utilizzare l'overload di XmlDocument.Load(XmlReader) invece di XmlDocument.LoadXml o uno qualsiasi di altri overload XmlDocument.Load, come illustrato in di Figura 6.

Nella figura 6 applicazione Entity più sicurezza nell'analisi delle impostazioni per XmlDocument

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 è leggermente più sicuro nelle impostazioni predefinite; XmlReader creato per impostazione predefinita per System.Xml.Linq.XDocument consente l'analisi di DTD, ma imposta MaxCharactersFromEntities a 10.000.000 automaticamente e non consente la risoluzione di entità esterna. Se si desidera fornire in modo esplicito un XmlReader a XDocument, assicurarsi di applicare le impostazioni di difesa descritte in precedenza.

Conclusioni

Espansione di entità XML è una funzionalità potente, ma può essere facilmente sfruttato da un utente malintenzionato di negazione del servizio all'applicazione. Assicurarsi di seguire il principio di riduzione della superficie di attacco e disattivare l'espansione delle entità se si non richiesta l'utilizzo. In caso contrario, applicare le difese appropriate per limitare la quantità massima di tempo e della memoria che dell'applicazione può dedicare su di esso.

Bryan Sullivan è un protezione program manager del team a Microsoft Security Development Lifecycle, specializzato in applicazione Web e .NET problemi di protezione. È autore di “ AJAXSecurity ” (Addison-Wesley, 2007).