Compartir a través de


Este artículo proviene de un motor de traducción automática.

Pinceladas sobre seguridad

Denegación de XML de defensas y ataques de servicios

Bryan Sullivan

Ataques de denegación de servicio (DoS) se encuentran entre los tipos de ataques contra sitios Web más antiguos. Documentado DoS ataques existen al menos hasta donde reverso sea 1992, que es anterior a la inyección de SQL (descubierta en 1998), entre sitios de secuencias de comandos (JavaScript no fue inventado hasta 1995) y la falsificación de solicitud entre sitios (CSRF ataques suelen requieran las cookies de sesión y cookies no se han introducido hasta 1994).

Desde el principio, ataques DoS eran muy populares con la comunidad de piratas informáticos y resulta fácil comprender por qué. Un atacante “ bromista de secuencias de comandos ” único con una cantidad mínima de cualificación y recursos puede generar una avalancha de peticiones TCP SYN (para sincronizar) suficientes para debe aplicarse la reserva de color un sitio fuera de servicio. El mundo del comercio electrónico fledgling, esto era devastadores: Si no se pudieron obtener los usuarios a un sitio, no se pudo muy bien dedican dinero existe bien. Los ataques doS eran el equivalente virtual de erecting afeitar hilos fence alrededor de un almacén de ladrillos tradicionales, salvo que cualquier almacén podría verse a cualquier hora, día o por la noche.

En los años, las mejoras en hardware de red y software de servidor Web han ha mitigado en gran medida los ataques de desbordamiento SYN. Sin embargo, últimamente ha habido un resurgence de interés en ataques DoS dentro de la comunidad de seguridad, no para “ antiguo escuela ” red nivel DoS, sino para DoS de nivel de aplicación y especialmente para el Analizador XML de DoS.

Ataques XML DoS son extremadamente asimétricos: para entregar la carga de ataque, un atacante necesita dedicar sólo una fracción del ancho de banda que la víctima necesita dedicar para controlar la carga o capacidad de procesamiento. Peor aún, DoS vulnerabilidades en código que procesa XML también son muy generalizadas. Incluso si está utilizando analizadores probados exhaustivamente como las que se encuentran en las clases System.XML de Microsoft .NET Framework, el código puede quedar vulnerable a menos que realice pasos explícitos para protegerlo.

Este artículo describe algunos de los nuevos ataques de DoS de XML. También muestra métodos detectar posibles vulnerabilidades de DoS y cómo mitigarlos en el código.

Bombas XML

Un tipo de ataque de DoS de XML especialmente desagradable es la bomba XML — un bloque de XML que tiene el formato correcto y válido de acuerdo con las reglas de un esquema XML, pero que se bloquea o bloquea un programa cuando ese programa intenta analizarlo. El ejemplo de una bomba XML best-known probablemente es el ataque de expansión de entidad exponencial.

Dentro de una definición de tipo de documento XML (DTD), puede definir sus propias entidades, que esencialmente actúan como macros de sustitución de cadena. Por ejemplo, podría agregar esta línea a la DTD para reemplazar todas las apariciones de la cadena &companyname; con “ Contoso Inc. ”:

<!ENTITY companyname "Contoso Inc.">

También puede anidar las entidades, como éste:

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

Aunque la mayoría de los desarrolladores está familiarizada con el uso de archivos DTD externos, también es posible incluir DTD en línea junto con los propios datos XML. Definir simplemente la DTD directamente en el <! DOCTYPE > declaración en lugar de utilizar <! DOCTYPE > para hacer referencia a un archivo DTD externo:

<?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 atacante puede ahora aprovechar estas tres propiedades de XML (sustitución entidades, entidades anidadas y DTD en línea) para elaborar una bomba XML malintencionada. El atacante escribe un documento XML con entidades anidadas, al igual que el ejemplo anterior, pero en lugar de anidamiento de un solo nivel más profundo, nidos sus entidades muchos niveles profunda, tal como se muestra aquí:

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

Debe tenerse en cuenta que este XML es válido conforme a las reglas de la DTD y. Cuando este documento carga un analizador XML, ve que incluye un elemento raíz, “ lolz ”, que contiene el texto “ &lol9; ”. Sin embargo, “ &lol9; ” es una entidad definida que se expande a una cadena que contiene diez “ &lol8; ” cadenas. Cada “ &lol8; ” cadena es una entidad definida que se expande a diez “ &lol7; ” cadenas y así sucesivamente. Después de que se hayan procesado todas las expansiones de las entidad, este pequeño bloque de (< 1 KB) de XML realmente contendrá un millones “ lol ” s, ocupando casi 3 GB de memoria!  Puede intentar este ataque (a veces se denomina el ataque Laughs mil millones) para usted mismo usando este bloque de código muy sencillo; simplemente estar preparado para eliminar el proceso de aplicación de prueba desde el Administrador de tareas:

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

Algunos de los lectores más complicados que se esté preguntando en este momento si es posible crear una expansión de entidad infinitamente recursing que consta de dos entidades que hacen referencia entre sí:

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

Esto sería un ataque muy eficaz, pero Afortunadamente no es legal XML y no se analizará. Sin embargo, otra variación de la bomba exponencial XML de expansión de entidad que funciona es el ataque explotando cuadrática, descubierto por Amit Klein, de Trusteer. En lugar de definir varias entidades profundamente anidadas, pequeñas, el atacante define una entidad muy grande y hace referencia a él muchas veces:

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

Si un atacante define la entidad “ &a; ” como 50.000 caracteres de largo y hace referencia a que la entidad 50.000 veces dentro del elemento de “ kaboom ” raíz, termina con una carga de ataque de bomba ligeramente más de 200 KB de tamaño que se expande a 2,5 GB cuando analiza XML. Esta proporción de expansión no es bastante tan impresionante como con el ataque de expansión de entidad exponencial, pero es aún suficiente tomar hacia abajo el proceso de análisis.

Otra de descubrimientos de bomba de Klein XML es el ataque explotando de atributo. Muchos más antiguos analizadores XML, los de runtime de .NET Framework versiones 1.0 y 1.1, analizar los atributos XML en una O cuadrática extremadamente ineficaz (2 de n ) incluidos. Creando un documento XML con un gran número de atributos (por ejemplo 100.000 o más) para un solo elemento, el Analizador XML se monopolice el procesador durante un largo período de tiempo y por lo tanto causar una condición de denegación de servicio. Sin embargo, esta vulnerabilidad se ha corregido en versiones de .NET Framework 2.0 y posterior.

Ataques externos de entidad

En lugar de definir cadenas de reemplazo de entidad como constantes, también es posible definirlos para que sus valores se extraen de URI externos:

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

Mientras el comportamiento exacto depende de la implementación de analizador XML determinada, la intención aquí es que cada vez que el Analizador XML encuentra la entidad “ &stockprice; ” el analizador se realiza una solicitud a www.contoso.com/currentstockprice.ashx y a continuación, sustituya la respuesta recibida desde esa solicitud para la entidad de stockprice. Esto es indudablemente una característica interesante y útil de XML, pero también permite algunos ataques DoS tortuosos.

Es la forma más sencilla de abusar de su funcionalidad de la entidad externa enviar el Analizador XML a un recurso que nunca devolverá; es decir, para enviar en un infinito espera bucle. Por ejemplo, si un atacante tuviera control de adatum.com el servidor, se puede configurar un archivo de controlador HTTP genérico en http://adatum.com/dos.ashx como sigue:

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

A continuación, podría diseñar una entidad malintencionada que apuntaba a http://adatum.com/dos.ashx y cuando el Analizador XML lee el archivo XML, el analizador podría bloquearse. Sin embargo, esto no es un ataque especialmente efectivo. Es el punto de un ataque DoS a consumir recursos para que no está disponible para los usuarios legítimos de la aplicación. Nuestros ejemplos anteriores de expansión de entidad exponencial y XML explotando cuadrática bombas provocó el servidor para utilizar grandes cantidades de memoria y tiempo de CPU, pero no en este ejemplo. Todo este ataque consume realmente es un único subproceso de ejecución. Let’s mejorar este ataque (desde la perspectiva del atacante) obligando al servidor que consumen algunos recursos:

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

Este código escribirá un número infinito de ‘ A ’ secuencia de caracteres (un millón en un momento) a la respuesta y chew hasta una enorme cantidad de memoria en un tiempo muy corto. Si el atacante es no se puede o no puede configurar una página de su propietario para este propósito, quizás que no desea que deje un rastro de evidencia que señala a él, puede señalar en su lugar la entidad externa a un recurso muy grande en un sitio Web de terceros. Descargas de película o el archivo pueden ser especialmente eficaces para este propósito; por ejemplo, la descarga de Visual Studio Professional 2010 beta es más de 2 GB.

Aún otra variación ingenioso de este ataque es una entidad externa los señale un recursos de intranet del servidor de destino. Descubrimiento de esta técnica de ataque se abonará a Steve Orrin de Intel. Esta técnica requiere el atacante tener conocimiento interno de sitios de intranet accesibles por el servidor, pero si se puede ejecutar un ataque de recursos de intranet, puede ser especialmente eficaz porque el servidor dedica sus propios recursos (tiempo de procesador, ancho de banda y memoria) a los ataques o de sus servidores relacionado en la misma red.

Defensa contra bombas XML

La forma más sencilla de defenderse contra todos los tipos de ataques de entidad XML es simplemente deshabilitar por completo el uso de esquemas DTD en línea en los objetos de análisis de XML. Esto es una sencilla aplicación del principio de reducción de superficie de ataque: Si no utiliza una característica, desactívela para que los atacantes no podrán abusar de él.

En versiones de .NET Framework 3.5 y versiones anterior, comportamiento de análisis de DTD está controlado por la propiedad Boolean ProhibitDtd que se encuentran en las clases System.Xml.XmlTextReader y System.Xml.XmlReaderSettings. Establecer este valor a true para deshabilitar 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);

El valor predeterminado de ProhibitDtd en XmlReaderSettings es true, pero el valor predeterminado de ProhibitDtd en XmlTextReader es false, lo que significa que tiene que establecer explícitamente a true para deshabilitar inline DTD.

En .NET Framework, versión 4.0 (en versión beta en el momento de escribir este artículo), se ha cambiado el comportamiento de análisis de DTD. La propiedad ProhibitDtd quedó obsoleta en favor de la propiedad DtdProcessing nueva. Puede establecer esta propiedad en Prohibir (el valor predeterminado) para que el motor en tiempo de ejecución produce una excepción si un <! DOCTYPE > elemento está presente en el XML:

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

Como alternativa, puede establecer la propiedad DtdProcessing a omitir, que no se iniciará una excepción en encontrar un <! DOCTYPE > elemento pero se simplemente omita y no la procesa. Por último, puede establecer DtdProcessing a Parse si desea permitir y procesar DTD en línea.

Si realmente desea analizar DTD, debe seguir algunos pasos adicionales para proteger el código. El primer paso es limitar el tamaño de las entidades expandidas. Recuerde que los ataques que he tratado funcionan mediante la creación de entidades que se expanden a cadenas enormes y forzar al analizador que consumen grandes cantidades de memoria. Estableciendo la propiedad MaxCharactersFromEntities del objeto XmlReaderSettings puede rematar el número de caracteres que se pueden crear a través de las expansiones de entidad. Determinar un máximo razonable y establezca la propiedad en consecuencia. Aquí se muestra un ejemplo:

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

Defensa contra entidades externas

En este punto, nos hemos reforzado este código de modo que es mucho menos vulnerable a bombas XML, pero nos aún no hemos tratado los peligros que supone malintencionadas entidades externas. Si personaliza el comportamiento de XmlReader cambiando su XmlResolver se puede mejorar la resistencia contra estos ataques. Se utilizan objetos de XmlResolver para resolver referencias externas, incluidas las entidades externas. Instancias de XmlTextReader, así como instancias de XmlReader devueltas por llamadas a XmlReader.Create, se rellena previamente con predeterminada XmlResolvers (XmlUrlResolvers realmente). Puede impedir que XmlReader resolver entidades externas mientras sigue permitiendo que resolver entidades en línea estableciendo la propiedad XmlResolver de XmlReaderSettings en null. Se trata de reducción de superficie de ataques en el trabajo nuevo; si no necesita la capacidad, desactívelo:

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

Si esta situación no se aplica a la, si realmente, realmente tiene que resolver entidades externas — esperanza todos no se pierden, pero tiene un poco más trabajo por hacer. Para realizar XmlResolver más resistente a ataques de denegación de servicio, deberá cambiar su comportamiento de tres maneras. En primer lugar, deberá establecer un tiempo de espera de solicitud para evitar ataques de retraso infinito. En segundo lugar, deberá limitar la cantidad de datos que se recuperará. Por último, como medida de defensa en profundidad, debe restringir el XmlResolver de recuperar recursos en el host local. Puede hacer todo esto mediante la creación de una clase XmlResolver personalizada.

El comportamiento que desea modificar se rige por el método GetEntity de XmlResolver. Cree una nueva clase derivada de XmlSafeResolver de XmlUrlResolver y reemplazar el método GetEntity como sigue:

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

    }
}

El comportamiento predeterminado del método XmlUrlResolver.GetEntity parece el código siguiente, que puede utilizar como punto de partida para su implementación:

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

El primer cambio es aplicar los valores de tiempo de espera al realizar la solicitud y al leer la respuesta. El System.NET.WebRequest y las clases de System.IO.Stream proporcionan compatibilidad inherente para tiempos de espera. En el ejemplo de código se muestra en de figura 1, puedo simplemente codificar el valor de tiempo de espera, pero se puede exponer fácilmente una propiedad pública de Timeout en la clase XmlSafeResolver si desea mayor capacidad de configuración.

Figura 1 de valores de configuración Timeout

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

El paso siguiente es rematar la cantidad máxima de datos que se recuperan en la respuesta. No hay ninguna propiedad “ MaxSize ” o el equivalente para la clase Stream, tener que implementar esta funcionalidad usted mismo. Para ello, puede leer datos desde el fragmento de una secuencia de respuesta a la vez y cópielo en una caché local de la secuencia. Si el número total de bytes leídos de la secuencia de respuesta supera un límite predefinido (nuevo codificado por simplicidad sólo), detenga la lectura de la secuencia y produce una excepción (consulte de figura 2).

Figura 2 de combinación y minúsculas de la cantidad máxima de datos recuperados

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

Como alternativa, puede ajustar la clase Stream y implementar el límite de comprobación directamente en el método reemplazado de lectura (consulte de figura 3). Ésta es una implementación más eficaz, ya que guardar la memoria adicional asignada para MemoryStream en caché en el ejemplo anterior.

Figura 3 definir un tamaño-limitados clase contenedora de Stream

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

    ...
}

Ahora, simplemente ajustar la secuencia devuelta desde WebResponse.GetResponseStream en un LimitedStream y devolver el LimitedStream desde el método GetEntity (consulte de figura 4).

Figura 4 Using LimitedStream en 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);
}

Por último, agregue una medida de defensa en profundidad más bloqueando la resolución de entidades de URI que resuelven la .estos host local (consulte de figura 5) incluye a URI empezando con http://localhost, http://127.0.0.1 y URI file://. Tenga en cuenta que esto también evita que una vulnerabilidad de divulgación de información muy desagradable en el que los atacantes pueden elaborar entidades que señala a file://resources, el contenido de los cuales está a continuación, debidamente recupera y escriben en el documento XML por el analizador.

Figura 5 de bloqueo de resolución de la entidad de host local

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

Ahora que ha definido un XmlResolver más seguro, deberá aplicarla a XmlReader. Crear una instancia explícita de un objeto XmlReaderSettings, establecer la propiedad XmlResolver a una instancia de XmlSafeResolver y, a continuación, utilizar el XmlReaderSettings al crear XmlReader, tal como se muestra aquí:

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

Consideraciones adicionales

Es importante tener en cuenta que en muchas de las clases System.XML, si un XmlReader no se proporciona explícitamente a un objeto o a un método, a continuación, uno está creado implícitamente para él en el código del marco de trabajo. Esto crea implícitamente XmlReader no tendrá ninguna de las defensas adicionales especificadas en este artículo, y será vulnerable a ataques. El primer fragmento de código en este artículo es un buen ejemplo de este comportamiento:

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

Este código es vulnerable por completo a todos los ataques que se describen en este artículo. Para mejorar este código, explícitamente crear un XmlReader con la configuración apropiada (bien deshabilitar DTD en línea de análisis o especifica una clase de resolución más segura) y utilice la sobrecarga de XmlDocument.Load(XmlReader) en lugar de XmlDocument.LoadXml o cualquiera de las demás sobrecargas XmlDocument.Load, como se muestra en de figura 6.

Figura 6 de aplicar la configuración para XmlDocument de análisis de entidad más seguro

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 es algo más seguro en su configuración predeterminada; el XmlReader creado de forma predeterminada para System.Xml.Linq.XDocument permite analizar DTD pero automáticamente MaxCharactersFromEntities se establece en 10.000.000 y prohíbe la resolución de la entidad externa. Si proporciona explícitamente un XmlReader para XDocument, asegúrese de aplicar la configuración defensiva descrita anteriormente.

Conclusión

Expansión de entidad XML es una característica eficaz, pero puede fácilmente ser abused por un atacante para denegar el servicio a la aplicación. Asegúrese de seguir el principio de reducción de superficie de ataque y deshabilitar la expansión de entidad si no requieren su uso. De lo contrario, se aplican las defensas adecuadas para limitar la cantidad máxima de tiempo y memoria que puede dedicar su aplicación en él.

Bryan Sullivan es un administrador de programas de seguridad para el equipo de Microsoft Security Development Lifecycle, especializado en la aplicación Web y .NET problemas de seguridad. Es el autor de “ AJAXSecurity ” (Addison-Wesley, 2007).