Cet article a fait l'objet d'une traduction automatique.
Sécurité
Attaques par déni de service XML et moyens de défense
Bryan Sullivan
Attaques par déni de service (DoS) comptent parmi les plus anciens types d'attaques contre des sites Web. DoS documentées attaques existent au moins autant arrière que 1992, a supplanté (découverte en 1998) l'injection SQL, cross-site scripting (JavaScript n'a pas été inventé jusqu'à 1995) et cross-site contrefaçon de requête (CSRF attaques requièrent généralement des cookies de session et cookies n'ont pas été introduites jusqu'à 1994).
À partir du début, les attaques par déni de service ont été très populaires avec la communauté de pirate, et il est facile à comprendre pourquoi. Un attaquant “ script kiddie respectez unique avec un minimum de compétence et de ressources peut générer un flot de requêtes TCP SYN (pour la synchronisation) suffisantes pour masquer un site de service. Pour le monde fledgling de commerce électronique, ceci était dévastatrices : Si les utilisateurs n'a pas pu accéder à un site, ils n'ont pas pu très bien dépenser il soit. Les attaques par déni de service ont été l'équivalent virtuel d'erecting rasoir fils fence autour d'une banque de brique et être utilisées, sauf que n'importe quel magasin peut être attaqué à n'importe quelle heure, jour ou de la nuit.
Au fil des années, les attaques de submersion SYN ont été atténuées en grande partie par les améliorations dans un matériel de logiciels et réseau de serveur Web. Toutefois, ces derniers temps a été un resurgence d'intérêt dans les attaques par déni de service au sein de la communauté de sécurité — pas pour “ ancien école respectez au niveau du réseau DoS, mais plutôt de refus de service au niveau de l'application et en particulier pour l'analyseur XML déni de service.
Attaques de refus de service XML sont extrêmement asymétriques : Pour distribuer la surcharge d'attaque, un attaquant doit consacrer seulement une fraction de la puissance de traitement ou de la bande passante nécessaires à la victime à dépenser pour gérer la charge utile. Pire encore, les vulnérabilités de déni de service dans le code qui traite du XML sont également très répandues. Même si vous utilisez des analyseurs minutieusement testés tels que ceux trouvés dans les classes Microsoft .NET Framework System.XML, votre code peut être encore vulnérable, sauf si vous adoptez des mesures explicites pour les protéger.
Cet article décrit certaines des nouvelles attaques de refus de service XML. Il montre également les méthodes vous permettant de détecter les vulnérabilités potentielles de refus de service et de les atténuer dans votre code.
XML bombes
Un type d'attaque de refus de service XML particulièrement nocif est la bombe XML — un bloc de XML qui est bien formé et valide conformément aux règles d'un schéma XML, mais qui se bloque ou bloque un programme lorsque ce programme tente de l'analyser. L'exemple connue d'une bombe XML est probablement l'attaque exponentiel développement d'entité.
À l'intérieur d'une XML définition de type de document (DTD), vous pouvez définir vos propres entités, qui jouent essentiellement le rôle de macros de substitution de chaîne. Par exemple, vous pouvez ajouter cette ligne à votre DTD pour remplacer toutes les occurrences de la chaîne &companyname; avec “ Contoso Inc. respectez :
<!ENTITY companyname "Contoso Inc.">
Vous pouvez également imbriquer des entités, comme suit :
<!ENTITY companyname "Contoso Inc.">
<!ENTITY divisionname "&companyname; Web Products Division">
Alors que la plupart des développeurs sont familiarisés avec l'utilisation de fichiers DTD externes, il est également possible d'inclure des DTD inline avec les données XML lui-même. Vous définissez simplement la DTD directement dans le <! DOCTYPE > déclaration au lieu d'utiliser <! DOCTYPE > pour faire référence à un fichier DTD externe :
<?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 attaquant peut désormais tirer parti de ces trois propriétés de XML (substitution entités, entités imbriquées et inline DTD) pour concevoir une bombe XML malveillant. L'utilisateur malveillant écrit un document XML avec des entités imbriquées à l'instar de l'exemple précédent, mais au lieu d'imbrication qu'un niveau au-dessous, il imbrique ses entités nombreux niveaux de profondeur, comme illustré ici :
<?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>
Il convient de noter que ce code XML est bien formé et valide conformément aux règles de la DTD. Lorsqu'un analyseur XML, ce document est chargé, il voit qu'il comprend un seul élément racine, “ lolz respectez, qui contient le texte “ &lol9; respectez. Toutefois, “ &lol9; respectez est une entité définie qui se développe en une chaîne qui contient dix “ &lol8; respectez chaînes. Chaque “ &lol8; respectez chaîne est une entité définie qui se développe pour dix “ &lol7; respectez chaînes et ainsi de suite. Une fois que toutes les expansions entité ont été traitées, ce petit bloc de (< 1 Ko) de XML contiendra effectivement un milliard “ lol respectez s, occupent de pratiquement 3 Go de mémoire ! Vous pouvez essayer cette attaque (parfois appelée l'attaque rit milliards) pour vous-même à l'aide de ce bloc de code très simple, préparez-vous simplement votre processus d'application de test à partir du Gestionnaire des tâches :
void processXml(string xml)
{
System.Xml.XmlDocument document = new XmlDocument();
document.LoadXml(xml);
}
Parmi les lecteurs plus détournés peuvent se demander à ce stade s'il est possible de créer une expansion d'entité indéfiniment recursing consistant en deux entités qui font référence à l'autre :
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol1 "&lol2;">
<!ENTITY lol2 "&lol1;">
]>
<lolz>&lol1;</lolz>
Ce serait une attaque très efficace, mais heureusement, il n'est pas légal XML et ne pas analyse. Toutefois, une autre variante de la bombe exponentiel entité d'extension XML qui fonctionne est l'attaque agrandissement quadratique découvert par Amit Klein de Trusteer. Au lieu de définir plusieurs entités imbriquées, petites, l'attaquant définit une entité très volumineuse et y fait référence autant de fois :
<?xml version="1.0"?>
<!DOCTYPE kaboom [
<!ENTITY a "aaaaaaaaaaaaaaaaaa...">
]>
<kaboom>&a;&a;&a;&a;&a;&a;&a;&a;&a;...</kaboom>
Si un attaquant définit l'entité “ &a; respectez que 50 000 caractères et fait référence à qu'entité 50 000 fois à l'intérieur de l'élément de “ boum respectez racine, il finit avec une charge d'attaque par bombe XML légèrement plus de 200 Ko dans taille se développe pour 2,5 Go lorsque analysé. Ce ratio d'expansion n'est pas tout à fait comme impressionnant comme avec l'attaque exponentiel développement d'entité, mais il est toujours suffisamment pour arrêter le processus d'analyse.
Un autre XML bombe découvertes de Klein est l'attaque d'agrandissement de l'attribut. De nombreux anciens analyseurs XML, y compris ceux présents dans le .NET Framework versions 1.0 et 1.1, analyser les attributs XML dans un O quadratique très inefficace (2 n ) runtime. En créant un document XML avec un grand nombre d'attributs (par exemple 100 000 ou plus) pour un seul élément, l'analyseur XML va monopolise le processeur pendant une longue période de temps et par conséquent, entraîner une condition de déni de service. Toutefois, cette vulnérabilité a été fixe dans les versions de .NET Framework 2.0 et versions ultérieures.
Attaques de l'entité externe
Au lieu de définir des chaînes de remplacement d'entité en tant que constantes, il est également possible de les définir de sorte que leurs valeurs sont extraites des URI externes :
<!ENTITY stockprice SYSTEM "https://www.contoso.com/currentstockprice.ashx">
Bien que le comportement exact dépend de l'implémentation d'analyseur XML particulière, le but ici est que chaque fois que l'analyseur XML rencontre l'entité “ &stockprice; respectez le va effectuer une demande à www.contoso.com/currentstockprice.ashx et remplacer par la réponse reçue à partir de cette demande de l'entité stockprice. Il s'agit sans doute d'une fonctionnalité intéressante et utile de XML, mais il permet également de certaines attaques de refus de service détournés.
Le moyen le plus simple d'abuser de la fonctionnalité de l'entité externe est d'envoyer l'analyseur XML à une ressource qui ne retournera jamais ; c'est-à-dire, à envoyer dans un infini patienter boucle. Par exemple, si un attaquant prend le contrôle de la serveur adatum.com, il peut configurer un fichier de gestionnaire HTTP générique à http://adatum.com/dos.ashx comme suit :
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; } }
}
Il pourrait ensuite créer une entité malveillante qui pointait vers http://adatum.com/dos.ashx et lorsque l'analyseur XML lit le fichier XML, l'analyseur peut se bloquer. Toutefois, cela n'est pas une attaque particulièrement efficace. Le point d'une attaque par déni de service consiste à consommer des ressources afin qu'ils ne sont pas accessibles aux utilisateurs légitimes de l'application. Nos exemples de développement d'entité exponentiel et XML agrandissement quadratique bombes antérieures a provoqué le serveur à utiliser de grandes quantités de mémoire et le temps processeur, mais n'est pas le cas de cet exemple. Tout ce que cette attaque consomme vraiment est un seul thread d'exécution. Let’s améliorer cette attaque (du point de vue de l'attaquant) en forçant le serveur de consommer des ressources :
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();
}
}
Ce code va écrire un nombre infini de ‘A’ caractères (un million à la fois) dans le flux de réponse et mâchent place une énorme quantité de mémoire dans un délai très court. Si l'attaquant est impossible ou refuse de configurer une page de son propre à cet effet — peut-être qu'il ne souhaite pas conserver une trace des preuves qui pointe vers lui, il peut pointer à la place de l'entité externe à une ressource très volumineuse sur un site Web tiers. Téléchargements de film ou le fichier peuvent être particulièrement efficaces dans ce but ; par exemple, le téléchargement de version bêta de Visual Studio Professional 2010 est plus de 2 Go.
Encore une autre variante intelligente de cette attaque est pour désigner une entité externe à une ressources de l'intranet du serveur cible. Découverte de cette technique d'attaque est créditée sur Steve Orrin de Intel. Cette technique nécessite l'agresseur d'avoir des connaissances internes des sites intranet accessibles par le serveur, mais si une attaque de ressource intranet peut être exécutée, elle peut être particulièrement efficace, car le serveur est dépenses ses propres ressources (temps processeur, la bande passante et la mémoire) aux attaques lui-même ou de ses serveurs frère sur le même réseau.
Défense contre les bombes XML
Pour vous défendre contre tous les types d'attaques d'entité XML, la méthode la plus simple consiste à simplement désactiver entièrement l'utilisation des schémas DTD inline dans vos objets de l'analyse XML. Il s'agit d'une simple application du principe de réduire la surface d'attaque : Si vous n'utilisez pas une fonctionnalité, désactivez-le afin que les pirates ne pourrez pas abuser il.
Dans les versions de .NET Framework 3.5 et versions antérieur, comportement de l'analyse de DTD est contrôlé par la propriété Boolean ProhibitDtd trouvée dans les classes System.Xml.XmlTextReader et System.Xml.XmlReaderSettings. Définir cette valeur à true pour désactiver inline DTD complètement :
XmlTextReader reader = new XmlTextReader(stream);
reader.ProhibitDtd = true;
ou
XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = true;
XmlReader reader = XmlReader.Create(stream, settings);
La valeur par défaut de ProhibitDtd dans XmlReaderSettings est true, mais la valeur par défaut de ProhibitDtd dans XmlTextReader a la valeur false, ce qui signifie que vous avez explicitement défini à true pour désactiver inline DTD.
Dans .NET Framework version 4.0 (en version bêta au moment de la rédaction de cet article), le comportement d'analyse de DTD a été modifié. La propriété ProhibitDtd a été dépréciée en faveur de la nouvelle propriété DtdProcessing. Vous pouvez définir cette propriété pour empêcher (valeur par défaut) faire en sorte que le runtime lève une exception si un <! DOCTYPE > élément est présent dans le code XML :
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
XmlReader reader = XmlReader.Create(stream, settings);
Vous pouvez également définir la propriété DtdProcessing à ignorer, ne lèvera pas d'une exception de rencontrer une <! DOCTYPE > élément mais va simplement ignorer et pas le traiter. Enfin, vous pouvez définir DtdProcessing pour analyse si vous voulez autoriser et traiter des DTD inline.
Si vous souhaitez réellement analyser des DTD, vous devez prendre quelques étapes supplémentaires pour protéger votre code. La première étape consiste à limiter la taille du développement des entités. N'oubliez pas que les attaques que j'ai avez abordé fonctionnent en créant des entités développent en chaînes énormes et forcer l'Analyseur de consommer de grandes quantités de mémoire. En définissant la propriété MaxCharactersFromEntities de l'objet XmlReaderSettings, vous pouvez MAJ. le nombre de caractères qui peuvent être créés par l'intermédiaire d'entité expansions. Déterminer une valeur maximale raisonnable et définir la propriété en conséquence. Voici un exemple :
XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.MaxCharactersFromEntities = 1024;
XmlReader reader = XmlReader.Create(stream, settings);
Défense contre les attaques de l'entité externe
À ce stade, nous ont renforcé ce code afin qu'il est beaucoup moins vulnérable aux bombes XML, mais nous n'avez pas encore résolu les risques posés par des entités externes malveillantes. Vous pouvez améliorer votre résilience contre ces attaques si vous personnalisez le comportement de XmlReader en modifiant son XmlResolver. Objets XmlResolver permet de résoudre les références externes, y compris des entités externes. Instances de XmlTextReader, ainsi que des instances de XmlReader retournées par des appels à XmlReader.Create, sont alors préremplies avec par défaut XmlResolvers (XmlUrlResolvers réellement). Vous pouvez empêcher XmlReader de résoudre des entités externes tout en l'autorisant à résoudre des entités inline en affectant à la propriété XmlResolver de XmlReaderSettings la valeur null. Il s'agit de réduire la surface d'attaque au travail à nouveau ; si vous n'avez pas besoin de la capacité, le désactiver :
XmlReaderSettings settings = new XmlReaderSettings();
settings.ProhibitDtd = false;
settings.MaxCharactersFromEntities = 1024;
settings.XmlResolver = null;
XmlReader reader = XmlReader.Create(stream, settings);
Si cette situation ne s'applique pas à vous, si vous vraiment, vraiment besoin résoudre des entités externes — espoir tous n'est pas perdue, mais vous avez un peu plus de travail à faire. Pour apporter XmlResolver plus résistants aux attaques par déni de service, vous devez modifier son comportement de trois manières. Tout d'abord, vous devez définir un délai d'expiration de la requête afin d'empêcher les attaques de délai infini. Ensuite, vous devez limiter la quantité de données il récupérera. Enfin, par mesure de défense en profondeur, vous devez limiter le XmlResolver de récupérer des ressources sur l'ordinateur hôte local. Vous pouvez faire tout cela en créant une classe XmlResolver personnalisée.
Le comportement que vous souhaitez modifier est régi par la méthode XmlResolver GetEntity. Créez une nouvelle classe dérivée de XmlSafeResolver de XmlUrlResolver et substituez la méthode GetEntity comme suit :
class XmlSafeResolver : XmlUrlResolver
{
public override object GetEntity(Uri absoluteUri, string role,
Type ofObjectToReturn)
{
}
}
Le comportement par défaut de la méthode XmlUrlResolver.GetEntity ressemble le code suivant, vous pouvez utiliser comme point de départ pour votre implémentation :
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();
}
Le premier changement consiste à appliquer des valeurs de délai d'attente en créant la demande et lors de la lecture de la réponse. Le System.NET.WebRequest et les classes de System.IO.Stream fournissent la prise en charge inhérente des délais d'attente. Dans l'exemple de code illustré dans de figure 1, j'ai simplement coder en dur la valeur du délai d'attente, mais vous pouvez facilement exposer une propriété de délai d'attente publique sur la classe XmlSafeResolver si vous souhaitez que les possibilités de configuration supérieure.
Figure 1 de valeurs de configuration du délai d'attente
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;
}
L'étape suivante consiste à majuscule de la quantité maximale de données sont récupérées dans la réponse. Il y a aucune propriété “ MaxSize respectez ou l'équivalent de la classe Stream, afin que vous avez besoin d'implémenter cette fonctionnalité vous-même. Pour ce faire, vous pouvez lire les données à partir du flux de réponse d'un segment à la fois et copiez-le dans un cache de flux local. Si le nombre total d'octets lus à partir du flux de réponse dépasse une limite prédéfinie (nouveau préprogrammé pour des raisons de simplicité uniquement), vous arrêter lecture à partir du flux et lève une exception (voir de la figure 2).
La figure 2 Capping du nombre maximal de données de récupération
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;
}
Comme alternative, vous pouvez encapsuler la classe Stream et implémenter la contrôle directement dans la méthode Read substituée de limite (voir de la figure 3). Il s'agit d'une implémentation plus efficace dans la mesure où vous enregistrez la mémoire supplémentaire allouée pour la mise en cache MemoryStream dans l'exemple précédent.
La figure 3 définition d'une taille-limité classe wrapper 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;
}
...
}
À présent, simplement encapsuler le flux retourné à partir de WebResponse.GetResponseStream dans un LimitedStream et renvoyer le LimitedStream à partir de la méthode GetEntity (voir de la figure 4).
De la figure 4 utilisation LimitedStream dans 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);
}
Enfin, ajoutez une mesure de défense en profondeur plus en bloquant les entités (résolution) d'URI de résoudre le .cette (voir de la figure 5) local ordinateur hôte inclut URI commençant par http://localhost, http://127.0.0.1 et URI file://. Notez que cela empêche également une vulnérabilité de divulgation d'informations très nocif dans lequel les intrus peuvent concevoir des entités en pointant sur file://resources, dont le contenu est ensuite dûment récupéré et écrit dans le document XML par l'analyseur.
La figure 5 de blocage de résolution d'entité hôte local
public override object GetEntity(Uri absoluteUri, string role,
Type ofObjectToReturn)
{
if (absoluteUri.IsLoopback)
return null;
...
}
Maintenant que vous avez défini un XmlResolver plus sécurisé, vous devez appliquer à XmlReader. Explicitement instancier un objet XmlReaderSettings, définissez la propriété XmlResolver à une instance de XmlSafeResolver, puis utilisez le XmlReaderSettings lors de la création de XmlReader, comme illustré ici :
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);
Considérations supplémentaires
Il est important de noter que dans la plupart des classes System.XML, si un XmlReader n'est pas fourni explicitement à un objet ou à une méthode, puis une est implicitement créée pour elle dans le code d'infrastructure. Cela implicitement créé XmlReader n'aura aucun les défenses supplémentaires spécifiés dans cet article, et il sera vulnérable aux attaques. Le tout premier extrait de code dans cet article est un bon exemple de ce comportement :
void processXml(string xml)
{
System.Xml.XmlDocument document = new XmlDocument();
document.LoadXml(xml);
}
Ce code est complètement vulnérable à toutes les attaques décrites dans cet article. Pour améliorer ce code et utilisez la surcharge de XmlDocument.Load(XmlReader) au lieu de XmlDocument.LoadXml ou une des autres surcharges XmlDocument.Load, comme dans de la figure 6 explicitement créer XmlReader avec les paramètres appropriés (soit DTD inline de désactiver l'analyse ou spécifie une classe de programme de résolution plus sûre).
De la figure 6 application plus sûr Entity lors du traitement des paramètres de 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 est un peu plus sûre dans ses paramètres par défaut ; XmlReader créé par défaut pour System.Xml.Linq.XDocument autorise l'analyse de DTD, mais elle définit MaxCharactersFromEntities pour 10 000 000 et interdit les entités externes (résolution) automatiquement. Si vous fournissez explicitement un XmlReader à XDocument, veillez à appliquer les paramètres défensives décrites précédemment.
Conclusion
Expansion d'entité XML est une fonctionnalité puissante, mais il peut facilement être abusé par l'attaquant de refus de service à votre application. Veillez à suivre le principe de réduire la surface d'attaque et désactiver l'expansion d'entité si vous ne nécessitent pas de son utilisation. Dans le cas contraire, appliquer des défenses appropriées pour limiter la quantité maximale de temps et de la mémoire de que votre application peut passer sur celui-ci.
Bryan Sullivan est un gestionnaire de programme de sécurité pour l'équipe Microsoft Security Development Lifecycle, spécialisé dans l'application Web et .NET, problèmes de sécurité. Il est l'auteur de “ AJAXSecurity respectez (Addison-Wesley, 2007).