Remarque
L’accès à cette page requiert une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page requiert une autorisation. Vous pouvez essayer de modifier des répertoires.
Lorsque vous traitez des données dans Windows Communication Foundation (WCF), vous devez prendre en compte un certain nombre de catégories de menaces. La liste suivante présente les classes de menace les plus importantes liées au traitement des données. WCF fournit des outils pour atténuer ces menaces.
Déni de service
Lors de la réception de données non approuvées, les données peuvent entraîner l’accès à une quantité disproportionnée de différentes ressources, telles que la mémoire, les threads, les connexions disponibles ou les cycles de processeur en provoquant des calculs longs. Une attaque par déni de service contre un serveur peut provoquer un blocage et ne pas pouvoir traiter les messages d’autres clients légitimes.
Exécution de code malveillant
Les données entrantes non approuvées entraînent l’exécution de code non prévu par le côté réception.
Divulgation d’informations
L’attaquant distant force la partie destinataire à répondre à ses demandes de manière à divulguer plus d’informations qu’elle ne l’entend.
Code User-Provided et sécurité d'accès au code
Un certain nombre d’emplacements dans l’infrastructure Windows Communication Foundation (WCF) exécutent le code fourni par l’utilisateur. Par exemple, le moteur de sérialisation DataContractSerializer peut appeler des accesseurs set de propriété fournis par l'utilisateur et des accesseurs get . L’infrastructure de canal WCF peut également appeler des classes dérivées fournies par l’utilisateur de la Message classe.
Il incombe à l’auteur du code de s’assurer qu’aucune faille de sécurité n’existe. Par exemple, si vous créez un type de contrat de données avec une propriété membre de données de type entier et, dans l’implémentation de l’accesseur set , allouez un tableau en fonction de la valeur de la propriété, vous exposez la possibilité d’une attaque par déni de service si un message malveillant contient une valeur extrêmement importante pour ce membre de données. En général, évitez les allocations basées sur les données entrantes ou un traitement long dans le code fourni par l’utilisateur (en particulier si un traitement long peut être provoqué par une petite quantité de données entrantes). Lorsque vous effectuez une analyse de sécurité du code fourni par l’utilisateur, veillez également à prendre en compte tous les cas d’échec (autrement dit, toutes les branches de code où les exceptions sont levées).
L’exemple ultime de code fourni par l’utilisateur est le code à l’intérieur de votre implémentation de service pour chaque opération. La sécurité de votre implémentation de service est votre responsabilité. Il est facile de créer par inadvertance des implémentations d’opérations non sécurisées qui peuvent entraîner des vulnérabilités de déni de service. Par exemple, une opération qui prend une chaîne et retourne la liste des clients d’une base de données dont le nom commence par cette chaîne. Si vous travaillez avec une base de données volumineuse et que la chaîne passée n’est qu’une seule lettre, votre code peut tenter de créer un message plus grand que toute la mémoire disponible, ce qui entraîne l’échec de l’ensemble du service. (Un OutOfMemoryException n’est pas récupérable dans le .NET Framework et entraîne toujours l’arrêt de votre application.)
Vous devez vous assurer qu’aucun code malveillant n’est branché aux différents points d’extensibilité. Cela est particulièrement pertinent lors de l’exécution en cas d’approbation partielle, de traitement des types provenant d’assemblys partiellement approuvés ou de création de composants utilisables par du code partiellement approuvé. Pour plus d’informations, consultez « Menaces de confiance partielle » dans une section ultérieure.
Notez qu’en cas d’exécution en confiance partielle, l’infrastructure de sérialisation des contrats de données ne prend en charge qu’un sous-ensemble limité du modèle de programmation du contrat de données ( par exemple, les membres de données privés ou les types utilisant l’attribut SerializableAttribute ne sont pas pris en charge). Pour plus d’informations, consultez Confiance partielle.
Remarque
La sécurité de l’accès au code (CAS) a été déconseillée dans toutes les versions de .NET Framework et .NET. Les versions récentes de .NET n’honorent pas les annotations CAS et produisent des erreurs si les API associées à CAS sont utilisées. Les développeurs doivent rechercher d’autres moyens d’accomplir des tâches de sécurité.
Éviter la divulgation d’informations involontaires
Lors de la conception de types sérialisables avec une sécurité à l’esprit, la divulgation d’informations est un problème possible.
Tenez compte des points suivants :
Le DataContractSerializer modèle de programmation permet l’exposition de données privées et internes en dehors du type ou de l’assembly pendant la sérialisation. En outre, la forme d’un type peut être exposée pendant l’exportation de schéma. Veillez à comprendre la projection de sérialisation de votre type. Si vous ne souhaitez rien exposer, désactivez sa sérialisation (par exemple, en n’appliquant pas l’attribut DataMemberAttribute dans le cas d’un contrat de données).
N’oubliez pas que le même type peut avoir plusieurs projections de sérialisation, en fonction du sérialiseur en cours d’utilisation. Le même type peut exposer un jeu de données lorsqu’il est utilisé avec le DataContractSerializer et un autre jeu de données lorsqu’il est utilisé avec le XmlSerializer. L’utilisation accidentelle du sérialiseur incorrect peut entraîner une divulgation d’informations.
L'utilisation de XmlSerializer en mode d'appel de procédure distante (RPC)/encodé hérité peut exposer involontairement la forme du graphique d'objets située sur le côté envoi au côté réception.
Prévention des attaques par déni de service
Contingents
Provoquer l’allocation d’une quantité importante de mémoire du côté récepteur est une attaque potentielle par déni de service. Bien que cette section se concentre sur les problèmes de consommation de mémoire résultant de messages volumineux, d’autres attaques peuvent se produire. Par exemple, les messages peuvent utiliser une durée de traitement disproportionnée.
Les attaques par déni de service sont généralement atténuées à l’aide de quotas. Lorsqu’un quota est dépassé, une QuotaExceededException exception est normalement levée. Sans le quota, un message malveillant peut entraîner l'accès à toute la mémoire disponible, entraînant une OutOfMemoryException exception, ou l'accès à toutes les piles disponibles, entraînant un StackOverflowException.
Le scénario de dépassement de quota est récupérable ; s’il est rencontré dans un service en cours d’exécution, le message en cours de traitement est ignoré et le service continue à s’exécuter et traite d’autres messages. Toutefois, les scénarios de mémoire insuffisante et de débordement de pile ne sont pas récupérables dans aucune partie du .NET Framework ; le service se termine s'il rencontre de telles exceptions.
Les quotas dans WCF n’impliquent aucune pré-allocation. Par exemple, si le MaxReceivedMessageSize quota (trouvé sur différentes classes) est défini sur 128 Ko, cela ne signifie pas que 128 Ko sont automatiquement alloués pour chaque message. La quantité réelle allouée dépend de la taille réelle du message entrant.
De nombreux quotas sont disponibles au niveau de la couche de transport. Il s’agit de quotas appliqués par le canal de transport spécifique en cours d’utilisation (HTTP, TCP, etc.). Bien que cette rubrique traite de certains de ces quotas, ces quotas sont décrits en détail dans Les quotas de transport.
Vulnérabilité de hachage
Il existe une vulnérabilité lorsque les contrats de données contiennent des tables de hachage ou des collections. Le problème se produit si un grand nombre de valeurs sont insérées dans une table de hachage où un grand nombre de ces valeurs génèrent la même valeur de hachage. Cela peut être utilisé comme attaque DOS. Cette vulnérabilité peut être atténuée en configurant le seuil MaxReceivedMessageSize de liaison. Vous devez prendre soin de définir ce quota afin d’éviter ces attaques. Ce quota place une limite supérieure sur la taille du message WCF. En outre, évitez d'utiliser des tables de hachage ou des collections dans les contrats de données.
Limitation de la consommation de mémoire sans diffusion en continu
Le modèle de sécurité autour des messages volumineux dépend de l’utilisation de la diffusion en continu. Dans le cas de base, non diffusé en continu, les messages sont mis en mémoire tampon. Dans ce cas, utilisez le quota MaxReceivedMessageSize sur TransportBindingElement ou sur les liaisons fournies par le système à des fins de protection contre les messages volumineux en limitant la taille maximale des messages auxquels accéder. Notez qu’un service peut traiter plusieurs messages en même temps, auquel cas ils sont tous en mémoire. Utilisez la fonctionnalité de régulation pour atténuer cette menace.
Notez également que MaxReceivedMessageSize ne place pas une limite supérieure sur la consommation de mémoire par message, mais la limite à l’intérieur d’un facteur constant. Par exemple, si le MaxReceivedMessageSize message est de 1 Mo et qu’un message de 1 Mo est reçu, puis désérialisé, une mémoire supplémentaire est nécessaire pour contenir le graphique d’objets désérialisé, ce qui entraîne une consommation totale de mémoire supérieure à 1 Mo. Pour cette raison, évitez de créer des types sérialisables qui pourraient entraîner une consommation significative de mémoire sans beaucoup de données entrantes. Par exemple, un contrat de données « MyContract » avec 50 champs membres de données facultatifs et 100 champs privés supplémentaires peuvent être instanciés avec la construction XML «< MyContract/> ». Ce code XML entraîne l’accès à la mémoire pour 150 champs. Notez que les éléments de données sont facultatifs par défaut. Le problème est aggravé lorsqu’un tel type fait partie d’un tableau.
MaxReceivedMessageSize seul n’est pas suffisant pour empêcher toutes les attaques par déni de service. Par exemple, le désérialiseur peut être forcé à désérialiser un graphique d'objets très imbriqué (un objet qui contient un autre objet qui en contient encore un autre, et ainsi de suite) par un message entrant.
DataContractSerializer et XmlSerializer appellent des méthodes d'une manière imbriquée pour désérialiser de tels graphiques. L'imbrication profonde des appels de méthode peut provoquer une StackOverflowExceptionirrécupérable. Cette menace est atténuée en définissant le MaxDepth quota pour limiter le niveau d’imbrication XML, comme indiqué dans la section « Utilisation de XML en toute sécurité » plus loin dans la rubrique.
La définition de quotas MaxReceivedMessageSize supplémentaires est particulièrement importante lors de l’utilisation de l’encodage XML binaire. L’utilisation de l’encodage binaire est un peu équivalente à la compression : un petit groupe d’octets dans le message entrant peut représenter un grand nombre de données. Ainsi, même un message correspondant à la MaxReceivedMessageSize limite peut occuper beaucoup plus de mémoire sous forme entièrement développée. Pour atténuer ces menaces spécifiques au code XML, tous les quotas de lecteur XML doivent être définis correctement, comme indiqué dans la section « Utilisation sécurisée de XML » plus loin dans cette rubrique.
Limitation de la consommation de mémoire avec streaming
Lors de la diffusion en continu, vous pouvez utiliser un petit MaxReceivedMessageSize paramètre pour vous protéger contre les attaques par déni de service. Toutefois, des scénarios plus compliqués sont possibles avec la diffusion en continu. Par exemple, un service de chargement de fichiers accepte des fichiers supérieurs à la mémoire disponible. Dans ce cas, définissez la MaxReceivedMessageSize valeur sur une valeur extrêmement importante, en s’attendant à ce que presque aucune donnée ne soit mise en mémoire tampon et que les flux de messages se trouvent directement sur le disque. Si un message malveillant peut en quelque sorte forcer WCF à mettre en mémoire tampon les données au lieu de la diffuser en continu dans ce cas, MaxReceivedMessageSize ne protège plus contre le message accédant à toute la mémoire disponible.
Pour atténuer cette menace, des paramètres de quota spécifiques existent sur différents composants de traitement des données WCF qui limitent la mise en mémoire tampon. Les plus importantes sont la propriété MaxBufferSize sur divers éléments de liaison de transport et les liaisons standard. Lors de la diffusion en continu, ce quota doit être défini en tenant compte de la quantité maximale de mémoire que vous êtes prêt à allouer par message. Comme avec MaxReceivedMessageSize, le paramètre ne met pas un maximum absolu sur la consommation de mémoire, mais le limite uniquement au sein d’un facteur constant. En outre, comme avec MaxReceivedMessageSize, sachez que plusieurs messages sont traités simultanément.
Détails de MaxBufferSize
La MaxBufferSize propriété limite toute mise en mémoire tampon en bloc de WCF. Par exemple, WCF met toujours en mémoire tampon les en-têtes SOAP et les fautes SOAP, ainsi que les parties MIME qui ne sont pas dans l'ordre de lecture naturel dans un message MTOM (Message Transmission Optimization Mechanism). Ce paramètre limite la quantité de mise en mémoire tampon dans tous ces cas.
WCF effectue cette opération en transmettant la MaxBufferSize valeur aux différents composants susceptibles de mettre en mémoire tampon. Par exemple, certaines surcharges CreateMessage de la classe Message acceptent un paramètre maxSizeOfHeaders . WCF transmet la MaxBufferSize valeur à ce paramètre pour limiter la quantité de mise en mémoire tampon d’en-tête SOAP. Il est important de définir ce paramètre directement lors de l’utilisation de la Message classe. En général, lors de l’utilisation d’un composant dans WCF qui prend des paramètres de quota, il est important de comprendre les implications de sécurité de ces paramètres et de les définir correctement.
L’encodeur de message MTOM a également un MaxBufferSize paramètre. Lorsque vous utilisez des liaisons standard, cette valeur est automatiquement définie en fonction de la valeur au niveau du transport MaxBufferSize. Toutefois, lors de l’utilisation de l’élément de liaison de l’encodeur de message MTOM pour construire une liaison personnalisée, il est important de définir la MaxBufferSize propriété sur une valeur sûre lors de l’utilisation du streaming.
Attaques de diffusion en continu basées sur XML
MaxBufferSize seul n’est pas suffisant pour garantir que WCF ne puisse être contraint à la mise en mémoire tampon quand on prévoit une diffusion en continu. Par exemple, les lecteurs XML WCF mettent toujours en mémoire tampon l’ensemble de la balise de démarrage de l’élément XML lors du démarrage de la lecture d’un nouvel élément. Cela permet de traiter correctement les espaces de noms et les attributs. S’il MaxReceivedMessageSize est configuré pour être volumineux (par exemple, pour activer un scénario de streaming de fichiers volumineux direct à disque), un message malveillant peut être construit où le corps du message entier est une balise de début d’élément XML volumineuse. Une tentative de le lire provoque une OutOfMemoryException. Il s’agit de l’une des nombreuses attaques par déni de service basées sur XML possibles qui peuvent toutes être atténuées à l’aide de quotas de lecteur XML, décrites dans la section « Utilisation sécurisée de XML » plus loin dans cette rubrique. Lors de la diffusion en continu, il est particulièrement important de définir tous ces quotas.
Mélange de modèles de programmation de streaming et de mise en mémoire tampon
De nombreuses attaques possibles proviennent de la combinaison de modèles de programmation de diffusion en continu et non de diffusion en continu dans le même service. Supposez qu'il existe un contrat de service contenant deux opérations : une qui prend un Stream et une autre qui prend un tableau de type personnalisé. Supposons également qu’elle MaxReceivedMessageSize est définie sur une valeur importante pour permettre à la première opération de traiter des flux volumineux. Malheureusement, cela signifie que des messages volumineux peuvent à présent être envoyés à la seconde opération, et que le désérialiseur met en mémoire tampon des données sous la forme d'un tableau avant d'appeler l'opération. Il s'agit d'une attaque par déni de service potentielle : le quota MaxBufferSize ne limite pas la taille du corps du message, avec laquelle le désérialiseur fonctionne.
Pour cette raison, évitez de mélanger les opérations basées sur un flux et non diffusées dans le même contrat. Si vous devez absolument combiner les deux modèles de programmation, utilisez les précautions suivantes :
Désactivez la fonctionnalité IExtensibleDataObject en définissant la propriété IgnoreExtensionDataObject de ServiceBehaviorAttribute sur
true. Cela garantit que seuls les membres qui font partie du contrat sont désérialisés.Définissez la propriété MaxItemsInObjectGraph à une valeur sûre pour DataContractSerializer. Ce quota est également disponible sur l’attribut ou via la ServiceBehaviorAttribute configuration. Ce quota limite le nombre d’objets désérialisés dans un épisode de désérialisation. Normalement, chaque paramètre d’opération ou partie corps de message dans un contrat de message est désérialisé dans un épisode. Lors de la désérialisation des tableaux, chaque entrée de tableau est comptabilisée comme un objet distinct.
Définissez tous les quotas de lecteur XML sur des valeurs sécurisées. Faites attention à MaxDepth, MaxStringContentLengthet MaxArrayLength et évitez les chaînes dans les opérations de non-diffusion en continu.
Passez en revue la liste des types connus, en gardant à l’esprit que l’un d’eux peut être instancié à tout moment (voir la section « Empêcher les types inattendus d’être chargés » plus loin dans cette rubrique).
N’utilisez aucun type qui implémente l’interface IXmlSerializable qui met en mémoire tampon un grand nombre de données. N’ajoutez pas de tels types à la liste des types connus.
N’utilisez pas les tableaux XmlElement, les tableaux XmlNode, les tableaux Byte ou les types qui implémentent ISerializable dans un contrat.
N'utilisez pas les tableaux XmlElement, XmlNode ou Byte, ni les types qui implémentent ISerializable dans la liste des types connus.
Les précautions précédentes s’appliquent lorsque l’opération non diffusée utilise le DataContractSerializer. Ne mélangez jamais les modèles de programmation de streaming et de programmation non-streaming sur le même service si vous utilisez le XmlSerializer, car il n’a pas la protection du MaxItemsInObjectGraph quota.
Attaques de flux lents
Une classe d’attaques par déni de service de streaming n’implique pas la consommation de mémoire. Au lieu de cela, l’attaque implique un expéditeur ou un récepteur de données lent. En attendant que les données soient envoyées ou reçues, les ressources telles que les threads et les connexions disponibles sont épuisées. Cette situation peut survenir à la suite d’une attaque malveillante ou d’un expéditeur/récepteur légitime sur une connexion réseau lente.
Pour réduire ces attaques, définissez correctement les délais d'attente de transport. Pour plus d’informations, consultez Quotas de transport. Deuxièmement, n’utilisez jamais d’opérations synchrones Read ou Write lors de l’utilisation de flux dans WCF.
Utilisation de XML en toute sécurité
Remarque
Bien que cette section concerne le code XML, les informations s’appliquent également aux documents JSON (JavaScript Object Notation). Les quotas fonctionnent de la même façon, à l’aide du mappage entre JSON et XML.
Lecteurs XML sécurisés
L’ensemble d’informations XML constitue la base de tous les traitements de messages dans WCF. Lors de l’acceptation de données XML à partir d’une source non approuvée, un certain nombre de possibilités d’attaque par déni de service existent qui doivent être atténuées. WCF fournit des lecteurs XML spéciaux et sécurisés. Ces lecteurs sont créés automatiquement lors de l’utilisation de l’un des encodages standard dans WCF (texte, binaire ou MTOM).
Certaines des fonctionnalités de sécurité sur ces lecteurs sont toujours actives. Par exemple, les lecteurs ne traitent jamais les définitions de type de document (DTD), qui sont une source potentielle d’attaques par déni de service et ne doivent jamais apparaître dans des messages SOAP légitimes. D’autres fonctionnalités de sécurité incluent des quotas de lecteur qui doivent être configurés, qui sont décrits dans la section suivante.
Lorsque vous travaillez directement avec des lecteurs XML (par exemple, lors de l’écriture de votre propre encodeur personnalisé ou lorsque vous travaillez directement avec la Message classe), utilisez toujours les lecteurs sécurisés WCF lorsqu’il y a une chance d’utiliser des données non approuvées. Créez les lecteurs sécurisés en appelant l'une des surcharges de méthode de fabrique statique de CreateTextReader, CreateBinaryReaderou CreateMtomReader sur la classe XmlDictionaryReader . Lors de la création d’un lecteur, transmettez des valeurs de quota sécurisées. N'appelez pas les surcharges de la méthode Create . Celles-ci ne créent pas de lecteur WCF. Au lieu de cela, un lecteur est créé qui n’est pas protégé par les fonctionnalités de sécurité décrites dans cette section.
Quotas de lecteur
Les lecteurs XML sécurisés ont cinq quotas configurables. Elles sont normalement configurées à l’aide de la ReaderQuotas propriété sur les éléments de liaison d’encodage ou les liaisons standard, ou à l’aide d’un XmlDictionaryReaderQuotas objet passé lors de la création d’un lecteur.
MaxBytesPerRead
Ce quota limite le nombre d’octets lus dans une seule Read opération lors de la lecture de la balise de début de l’élément et de ses attributs. (Dans les cas non diffusés en continu, le nom de l’élément lui-même n’est pas comptabilisé par rapport au quota.) MaxBytesPerRead est important pour les raisons suivantes :
Le nom de l’élément et ses attributs sont toujours mis en mémoire tampon lorsqu’ils sont lus. Par conséquent, il est important de définir ce quota correctement en mode streaming pour éviter une mise en mémoire tampon excessive lorsque la diffusion en continu est attendue. Reportez-vous à la section sur les quotas
MaxDepthci-dessous pour plus d'informations sur l'importance réelle de la mise en mémoire tampon qui se produit.L’utilisation d’un trop grand nombre d’attributs XML peut utiliser une durée de traitement disproportionnée, car les noms d’attributs doivent être vérifiés pour l’unicité.
MaxBytesPerReadatténue cette menace.
MaxDepth
Ce quota limite la profondeur maximale d’imbrication des éléments XML. Par exemple, le document «<A><B><C/></B></A>» a une profondeur d’imbrication de trois. MaxDepth est important pour les raisons suivantes :
MaxDepthinteragit avecMaxBytesPerRead: le lecteur conserve toujours les données en mémoire de l’élément actuel et de tous ses ancêtres, de sorte que la consommation maximale de mémoire du lecteur est proportionnelle au produit de ces deux paramètres.Lors de la désérialisation d'un graphique d'objets très imbriqué, le désérialiseur est obligé d'accéder à la pile entière et de lever une exception StackOverflowExceptionirrécupérable. Une corrélation directe existe entre l’imbrication XML et l’imbrication d’objets pour les éléments DataContractSerializer et XmlSerializer. Utilisez
MaxDepthpour atténuer cette menace.
MaxNameTableCharCount
Ce quota limite la taille de la table de noms du lecteur. La table de noms contient certaines chaînes (telles que les espaces de noms et les préfixes) rencontrées lors du traitement d’un document XML. Comme ces chaînes sont mises en mémoire tampon, définissez ce quota pour éviter une mise en mémoire tampon excessive lorsque la diffusion en continu est attendue.
MaxStringContentLength
Ce quota limite la taille de chaîne maximale retournée par le lecteur XML. Ce quota ne limite pas la consommation de mémoire dans le lecteur XML lui-même, mais dans le composant qui utilise le lecteur. Par exemple, lorsque le DataContractSerializer utilise un lecteur sécurisé par MaxStringContentLength, il ne désérialise pas les chaînes de caractères supérieures à ce quota. Lorsque vous utilisez la XmlDictionaryReader classe directement, toutes les méthodes ne respectent pas ce quota, mais uniquement les méthodes spécifiquement conçues pour lire des chaînes, telles que la ReadContentAsString méthode. La Value propriété sur le lecteur n’est pas affectée par ce quota et ne doit donc pas être utilisée lorsque la protection de ce quota est nécessaire.
MaxArrayLength
Ce quota limite la taille maximale d’un tableau de primitives que le lecteur XML retourne, y compris les tableaux d’octets. Ce quota ne limite pas la consommation de mémoire dans le lecteur XML lui-même, mais dans le composant qui utilise le lecteur. Par exemple, lorsque le DataContractSerializer utilise un lecteur sécurisé avec MaxArrayLength, il ne désérialise pas les tableaux d'octets plus grands que ce quota. Il est important de définir ce quota lorsque vous tentez de combiner des modèles de programmation en streaming et mis en mémoire tampon dans un seul contrat. N’oubliez pas que lorsque vous utilisez la XmlDictionaryReader classe directement, seules les méthodes spécifiquement conçues pour lire des tableaux de taille arbitraire de certains types primitifs, telles que ReadInt32Array, respectent ce quota.
Menaces spécifiques à l’encodage binaire
L'encodage XML binaire de WCF prend en charge la fonctionnalité des chaînes de dictionnaire. Une chaîne volumineuse peut être encodée à l’aide de quelques octets seulement. Cela permet des gains de performances significatifs, mais introduit de nouvelles menaces de déni de service qui doivent être atténuées.
Il existe deux types de dictionnaires : statiques et dynamiques. Le dictionnaire statique est une liste intégrée de chaînes longues qui peuvent être représentées à l’aide d’un code court dans l’encodage binaire. Cette liste de chaînes est corrigée lorsque le lecteur est créé et ne peut pas être modifié. Aucune des chaînes du dictionnaire statique utilisé par défaut par WCF ne sont suffisamment volumineuses pour poser une menace de déni de service grave, bien qu’elles puissent encore être utilisées dans une attaque d’extension de dictionnaire. Dans les scénarios avancés où vous fournissez votre propre dictionnaire statique, soyez prudent lors de l’introduction de chaînes de dictionnaire volumineuses.
La fonctionnalité dictionnaires dynamiques permet aux messages de définir leurs propres chaînes et de les associer à des codes courts. Ces mappages de chaîne à code sont conservés en mémoire pendant toute la session de communication, de sorte que les messages suivants n’ont pas à renvoyer les chaînes et peuvent utiliser des codes déjà définis. Ces chaînes peuvent être de longueur arbitraire et constituent donc une menace plus grave que celles du dictionnaire statique.
La première menace qui doit être atténuée est la possibilité que le dictionnaire dynamique (la table de mappage de chaîne à code) devienne trop volumineux. Ce dictionnaire peut être étendu au cours de plusieurs messages, et le MaxReceivedMessageSize quota n’offre donc aucune protection, car il s’applique uniquement à chaque message séparément. Par conséquent, une propriété distincte MaxSessionSize existe sur celle BinaryMessageEncodingBindingElement qui limite la taille du dictionnaire.
Contrairement à la plupart des autres quotas, ce quota s’applique également lors de l’écriture de messages. S'il est dépassé lors de la lecture d'un message, QuotaExceededException est levée comme d'habitude. S’il est dépassé lors de l’écriture d’un message, toutes les chaînes qui entraînent le dépassement du quota sont écrites as-is, sans utiliser la fonctionnalité de dictionnaires dynamiques.
Menaces d’extension de dictionnaire
Une classe importante d’attaques spécifiques au binaire provient de l’expansion du dictionnaire. Un petit message sous forme binaire peut se transformer en un message très volumineux sous forme textuelle entièrement développée s’il utilise largement la fonctionnalité dictionnaires de chaînes. Le facteur d’expansion des chaînes de dictionnaire dynamique est limité par le MaxSessionSize quota, car aucune chaîne de dictionnaire dynamique ne dépasse la taille maximale du dictionnaire entier.
Les propriétés MaxNameTableCharCount, MaxStringContentLength et MaxArrayLength limitent uniquement la consommation de mémoire. Ils ne sont normalement pas nécessaires pour atténuer les menaces dans l’utilisation non diffusée, car l’utilisation de la mémoire est déjà limitée par MaxReceivedMessageSize. Toutefois, MaxReceivedMessageSize compte les octets de préexpansion. Lorsque l’encodage binaire est en cours d’utilisation, la consommation de mémoire peut potentiellement aller au-delà MaxReceivedMessageSize, limitée uniquement par un facteur de MaxSessionSize. Pour cette raison, il est important de toujours définir tous les quotas de lecteur (en particulier MaxStringContentLength) lors de l’utilisation de l’encodage binaire.
Lors de l’utilisation de l’encodage binaire avec le DataContractSerializer, l’interface IExtensibleDataObject peut être mal utilisée pour monter une attaque d’extension de dictionnaire. Cette interface fournit essentiellement un stockage illimité pour les données arbitraires qui ne font pas partie du contrat. Si les quotas ne peuvent pas être définis suffisamment bas de sorte que MaxSessionSize multipliés par MaxReceivedMessageSize ne pose pas de problème, désactivez la IExtensibleDataObject fonctionnalité lors de l’utilisation de l’encodage binaire. Affectez à la propriété IgnoreExtensionDataObject la valeur true sur l'attribut ServiceBehaviorAttribute . Sinon, n’implémentez pas l’interface IExtensibleDataObject . Pour plus d’informations, consultez Forward-Compatible Contrats de données.
Résumé des quotas
Le tableau suivant récapitule les instructions relatives aux quotas.
| État | Quotas importants à définir |
|---|---|
| Aucune diffusion en continu ou diffusion en continu de petits messages, texte ou encodage MTOM |
MaxReceivedMessageSize, MaxBytesPerRead et MaxDepth |
| Aucune diffusion en continu ou diffusion en continu de petits messages, encodage binaire |
MaxReceivedMessageSize, MaxSessionSize et tous les ReaderQuotas |
| Diffusion en continu de messages volumineux, de texte ou d’encodage MTOM |
MaxBufferSize et tous les ReaderQuotas |
| Diffusion en continu de messages volumineux, encodage binaire |
MaxBufferSize, MaxSessionSize et tous les ReaderQuotas |
Les délais d'attente au niveau du transport doivent toujours être définis et ne jamais utiliser des lectures/écritures synchrones lorsque la diffusion en continu est utilisée, que vous diffusiez en continu des messages volumineux ou non.
En cas de doute sur un quota, définissez-le sur une valeur sûre plutôt que de le laisser ouvert.
Prévention de l’exécution de code malveillant
Les classes générales suivantes de menaces peuvent exécuter du code et avoir des effets inattendus :
Le désérialiseur charge un type malveillant, potentiellement dangereux ou sensible pour la sécurité.
Un message entrant provoque le désérialiseur à construire une instance d’un type généralement sûr d'une manière qui entraîne des conséquences inattendues.
Les sections suivantes décrivent plus en détail ces classes de menaces.
DataContractSerializer
(Pour plus d’informations sur la XmlSerializersécurité, consultez la documentation pertinente.) Le modèle de sécurité du modèle XmlSerializer est similaire à celui du DataContractSerializer, et diffère principalement en détails. Par exemple, l’attribut XmlIncludeAttribute est utilisé pour l’inclusion de type au lieu de l’attribut KnownTypeAttribute . Toutefois, certaines menaces uniques à XmlSerializer sont abordées plus loin dans cette rubrique.
Prévention du chargement de types involontaires
Le chargement de types inattendus peut avoir des conséquences significatives, que le type soit malveillant ou qu’il ait simplement des effets secondaires sensibles à la sécurité. Un type peut contenir une vulnérabilité de sécurité exploitable, effectuer des actions sensibles à la sécurité dans son constructeur ou constructeur de classe, avoir une empreinte mémoire importante qui facilite les attaques par déni de service ou peut lever des exceptions non récupérables. Les types peuvent avoir des constructeurs de classe qui s’exécutent dès que le type est chargé et avant la création d’instances. Pour ces raisons, il est important de contrôler le jeu de types que le désérialiseur peut charger.
DataContractSerializer désérialise d'une manière faiblement couplée. Il ne lit jamais les types et noms d’assemblage CLR (Common Language Runtime) à partir des données entrantes. Ceci est similaire au comportement du XmlSerializer, mais diffère du comportement du NetDataContractSerializer, BinaryFormatteret du SoapFormatter. Le couplage libre introduit un degré de sécurité, car l’attaquant distant ne peut pas indiquer un type arbitraire à charger simplement en nommant ce type dans le message.
DataContractSerializer est toujours autorisé à charger un type actuellement prévu conformément au contrat. Par exemple, si un contrat de données a un membre de données de type Customer, le DataContractSerializer est autorisé à charger le type Customer lorsqu’il désérialise ce membre de données.
En outre, le DataContractSerializer prend en charge le polymorphisme. Un membre de données peut être déclaré en tant que Object, mais les données entrantes peuvent contenir une Customer instance. Cela n’est possible que si le Customer type a été rendu « connu » au désérialiseur via l’un des mécanismes suivants :
KnownTypeAttribute attribut appliqué à un type.
KnownTypeAttributeattribut spécifiant une méthode qui retourne une liste de types.Attribut
ServiceKnownTypeAttribute.Section
KnownTypesde configuration.liste des types connus passée explicitement à DataContractSerializer pendant la construction, en cas d'utilisation directe du sérialiseur.
Chacun de ces mécanismes augmente la surface d'exposition en introduisant plus de types que le désérialiseur est capable de charger. Contrôlez chacun de ces mécanismes pour vous assurer qu’aucun type malveillant ou inattendu n’est ajouté à la liste des types connus.
Une fois qu'un type connu est dans le champ d'application, il peut être chargé à tout moment, et les instances du type peuvent être créées, même si le contrat interdit son utilisation. Par exemple, supposons que le type « MyDangerousType » est ajouté à la liste des types connus à l’aide de l’un des mécanismes ci-dessus. Cela signifie que :
MyDangerousTypeest chargé et son constructeur de classe s’exécute.Même lors de la désérialisation d'un contrat de données avec un membre de données de chaîne, un message malveillant peut quand même provoquer la création d'une instance de
MyDangerousType. Le code dansMyDangerousType, tel que les setters de propriétés, peut être exécuté. Une fois cette opération effectuée, le désérialiseur tente d’affecter cette instance au membre de données de type chaîne de caractères et échoue en générant une exception.
Lors de l’écriture d’une méthode qui retourne une liste de types connus ou lors de la transmission d’une liste directement au DataContractSerializer constructeur, assurez-vous que le code qui prépare la liste est sécurisé et fonctionne uniquement sur les données approuvées.
Si vous spécifiez des types connus dans la configuration, vérifiez que le fichier de configuration est sécurisé. Utilisez toujours des noms forts dans la configuration (en spécifiant la clé publique de l’assembly signé où réside le type), mais ne spécifiez pas la version du type à charger. Le chargeur de type sélectionne automatiquement la dernière version, si possible. Si vous spécifiez une version particulière dans la configuration, vous exécutez le risque suivant : un type peut avoir une vulnérabilité de sécurité qui peut être corrigée dans une version ultérieure, mais la version vulnérable se charge toujours, car elle est spécifiée explicitement dans la configuration.
Le fait d’avoir un trop grand nombre de types connus a une autre conséquence : le DataContractSerializer crée une cache de code de sérialisation et de désérialisation dans le domaine d'exécution, avec une entrée pour chaque type qu'il doit sérialiser et désérialiser. Ce cache n’est jamais effacé tant que le domaine d’application est en cours d’exécution. Par conséquent, un attaquant qui sait qu’une application utilise de nombreux types connus peut provoquer la désérialisation de tous ces types, ce qui entraîne l’utilisation d’une quantité disproportionnée de mémoire dans le cache.
Prévention des états involontaires affectés aux types
Un type peut avoir des contraintes de cohérence interne qui doivent être appliquées. Veillez à éviter de briser ces contraintes lors de la désérialisation.
L’exemple suivant d’un type représente l’état d’un verrou sur un vaisseau spatial et applique la contrainte que les portes intérieures et extérieures ne peuvent pas être ouvertes en même temps.
[DataContract]
public class SpaceStationAirlock
{
[DataMember]
private bool innerDoorOpenValue = false;
[DataMember]
private bool outerDoorOpenValue = false;
public bool InnerDoorOpen
{
get { return innerDoorOpenValue; }
set
{
if (value & outerDoorOpenValue)
throw new Exception("Cannot open both doors!");
else innerDoorOpenValue = value;
}
}
public bool OuterDoorOpen
{
get { return outerDoorOpenValue; }
set
{
if (value & innerDoorOpenValue)
throw new Exception("Cannot open both doors!");
else outerDoorOpenValue = value;
}
}
}
<DataContract()> _
Public Class SpaceStationAirlock
<DataMember()> Private innerDoorOpenValue As Boolean = False
<DataMember()> Private outerDoorOpenValue As Boolean = False
Public Property InnerDoorOpen() As Boolean
Get
Return innerDoorOpenValue
End Get
Set(ByVal value As Boolean)
If (value & outerDoorOpenValue) Then
Throw New Exception("Cannot open both doors!")
Else
innerDoorOpenValue = value
End If
End Set
End Property
Public Property OuterDoorOpen() As Boolean
Get
Return outerDoorOpenValue
End Get
Set(ByVal value As Boolean)
If (value & innerDoorOpenValue) Then
Throw New Exception("Cannot open both doors!")
Else
outerDoorOpenValue = value
End If
End Set
End Property
End Class
Un attaquant peut envoyer un message malveillant comme celui-ci, contourner les contraintes et obtenir l’objet dans un état non valide, ce qui peut avoir des conséquences inattendues et imprévisibles.
<SpaceStationAirlock>
<innerDoorOpen>true</innerDoorOpen>
<outerDoorOpen>true</outerDoorOpen>
</SpaceStationAirlock>
Cette situation peut être évitée en prenant en compte les points suivants :
Lorsque DataContractSerializer désérialise la plupart des classes, les constructeurs ne s'exécutent pas. Par conséquent, ne vous fiez pas à une gestion d'état effectuée dans le constructeur.
Utilisez des rappels pour vous assurer que l’objet est dans un état valide. Le rappel marqué avec l’attribut OnDeserializedAttribute est particulièrement utile, car il s’exécute une fois la désérialisation terminée et a la possibilité d’examiner et de corriger l’état global. Pour plus d’informations, consultez Rappels de sérialisation avec tolérance de version.
Ne concevez pas les types de contrats de données pour s’appuyer sur un ordre particulier dans lequel les setters de propriétés doivent être appelés.
Veillez à utiliser des types hérités marqués avec l’attribut SerializableAttribute . Beaucoup d’entre eux ont été conçus pour fonctionner avec le remoting .NET Framework à des fins d’utilisation avec des données approuvées uniquement. Les types existants marqués avec cet attribut n’ont peut-être pas été conçus avec la sécurité de l’état à l’esprit.
Ne vous fiez pas à la IsRequired propriété de l’attribut DataMemberAttribute pour garantir la présence de données en ce qui concerne la sécurité de l’état. Les données peuvent toujours être
null,zeroouinvalid.N’approuvez jamais un graphique d’objet désérialisé à partir d’une source de données non approuvée sans la valider en premier. Chaque objet individuel peut être dans un état cohérent, mais le graphique d’objet dans son ensemble peut ne pas être. En outre, même si le mode de conservation du graphique d’objet est désactivé, le graphe désérialisé peut avoir plusieurs références au même objet ou avoir des références circulaires. Pour plus d’informations, consultez Sérialisation et Désérialisation.
Utilisation sécurisée de NetDataContractSerializer
NetDataContractSerializer est un moteur de sérialisation qui utilise le couplage étroit des types. Ceci est similaire à BinaryFormatter et SoapFormatter. Autrement dit, il détermine le type à instancier en lisant l’assembly .NET Framework et le nom du type à partir des données entrantes. Bien qu’il s’agit d’une partie de WCF, il n’existe aucun moyen de brancher ce moteur de sérialisation ; le code personnalisé doit être écrit.
NetDataContractSerializer est fourni principalement pour faciliter la migration depuis le remoting .NET Framework vers WCF. Pour plus d’informations, consultez la section pertinente dans Sérialisation et Désérialisation.
Étant donné que le message lui-même peut indiquer que n’importe quel type peut être chargé, le NetDataContractSerializer mécanisme est intrinsèquement non sécurisé et doit être utilisé uniquement avec des données approuvées. Pour plus d’informations, consultez le Guide de sécurité de BinaryFormatter.
Même lorsqu'elles sont utilisées avec des données approuvées, les données entrantes peuvent insuffisamment spécifier le type à charger, en particulier si la propriété AssemblyFormat est définie à Simple. Toute personne ayant accès au répertoire de l’application ou au global assembly cache peut remplacer un type malveillant à la place de celui censé charger. Vérifiez toujours la sécurité du répertoire de votre application et du Global Assembly Cache en définissant correctement les autorisations.
En règle générale, si vous autorisez un accès de code partiellement approuvé à votre NetDataContractSerializer instance ou contrôlez le sélecteur de substitution (ISurrogateSelector) ou le classeur de sérialisation (SerializationBinder), le code peut exercer un grand contrôle sur le processus de sérialisation/désérialisation. Par exemple, il peut injecter des types arbitraires, entraîner une divulgation d’informations, altérer le graphe d'objet résultant ou les données sérialisées, ou déborder le flux sérialisé résultant.
Une autre préoccupation de sécurité concernant le NetDataContractSerializer est un déni de service, plutôt qu'une menace liée à l'exécution de code malveillant. Lorsque vous utilisez le NetDataContractSerializerquota, définissez toujours le MaxItemsInObjectGraph quota sur une valeur sûre. Il est facile de construire un petit message malveillant qui alloue un tableau d’objets dont la taille est limitée uniquement par ce quota.
Menaces propres à XmlSerializer
Le XmlSerializer modèle de sécurité est similaire à celui du DataContractSerializer. Toutefois, quelques menaces sont propres au XmlSerializer.
Les XmlSerializerassemblys de sérialisation générés au moment de l’exécution qui contiennent du code qui sérialise et désérialise réellement ; ces assemblys sont créés dans un répertoire de fichiers temporaires. Si un autre processus ou utilisateur dispose de droits d’accès à ce répertoire, il peut remplacer le code de sérialisation/désérialisation avec du code arbitraire. Ensuite, XmlSerializer exécute ce code à l’aide de son contexte de sécurité, au lieu du code de sérialisation/désérialisation. Vérifiez que les autorisations sont correctement définies sur le répertoire des fichiers temporaires pour empêcher cela.
Il XmlSerializer a également un mode dans lequel il utilise des assemblies de sérialisation prédéfinis au lieu de les générer en temps d'exécution. Ce mode est déclenché chaque fois que XmlSerializer peut détecter un assembly de sérialisation approprié. XmlSerializer effectue une vérification pour déterminer si l’assembly de sérialisation a été signé par la même clé que celle utilisée pour signer l’assembly contenant les types à sérialiser. Cela offre une protection contre les assemblages malveillants qui se font passer pour des assemblages de sérialisation. Toutefois, si l’assembly qui contient vos types sérialisables n’est pas signé, il XmlSerializer ne peut pas effectuer cette vérification et utilise n’importe quel assembly portant le nom correct. Cela permet d’exécuter du code malveillant. Signez toujours les assemblys qui contiennent vos types sérialisables, ou contrôlez étroitement l’accès au répertoire de votre application et au Global Assembly Cache pour empêcher l’introduction d’assemblys malveillants.
Le XmlSerializer peut faire l'objet d'une attaque par déni de service. Le XmlSerializer n’a pas de quota de MaxItemsInObjectGraph (comme celui disponible sur le DataContractSerializer). Ainsi, il désérialise une quantité arbitraire d’objets, limitée uniquement par la taille du message.
Menaces liées à la confiance partielle
Notez les préoccupations suivantes concernant les menaces liées au code s’exécutant avec une confiance partielle. Ces menaces incluent du code malveillant partiellement approuvé ainsi que du code malveillant partiellement approuvé en combinaison avec d’autres scénarios d’attaque (par exemple, du code partiellement approuvé qui construit une chaîne spécifique, puis le désérialiser).
Lorsque vous utilisez des composants de sérialisation, n’affirmez jamais d’autorisations avant cette utilisation, même si l’ensemble du scénario de sérialisation se trouve dans l’étendue de votre assertion et que vous ne traitez pas de données ou d’objets non approuvés. Cette utilisation peut entraîner des vulnérabilités de sécurité.
Dans les cas où le code partiellement approuvé contrôle le processus de sérialisation, soit par le biais de points d’extensibilité (substitution), de types sérialisés, soit par d’autres moyens, le code partiellement approuvé peut entraîner la sortie d’une grande quantité de données dans le flux sérialisé, ce qui peut entraîner un déni de service (DoS) au récepteur de ce flux. Si vous sérialisez des données destinées à une cible sensible aux menaces DoS, ne sérialisez pas les types partiellement approuvés et ne laissez pas le code partiellement approuvé contrôler la sérialisation.
Si vous autorisez l’accès du code de niveau de confiance partiel à votre instance DataContractSerializer, ou le contrôle des Substituts de contrats de données, il risque de contrôler une grande partie du processus de sérialisation/désérialisation. Par exemple, il peut injecter des types arbitraires, entraîner une divulgation d’informations, altérer le graphe d'objet résultant ou les données sérialisées, ou déborder le flux sérialisé résultant. Une menace équivalente NetDataContractSerializer est décrite dans la section « Using the NetDataContractSerializer Securely ».
Si l’attribut DataContractAttribute est appliqué à un type (ou au type marqué comme SerializableAttribute mais non ISerializable), le désérialiseur peut créer une instance de ce type même si tous les constructeurs ne sont pas publics ou protégés par des demandes.
N’approuvez jamais le résultat de la désérialisation, sauf si les données à désérialiser sont approuvées et que tous les types connus sont des types que vous approuvez. Notez que les types connus ne sont pas chargés à partir du fichier de configuration de l’application (mais sont chargés à partir du fichier de configuration de l’ordinateur) lors de l’exécution en confiance partielle.
Si vous passez une instance DataContractSerializer avec un substitut ajouté au code de niveau de confiance partiel, le code peut modifier tous les paramètres modifiables sur ce substitut.
Pour un objet désérialisé, si le lecteur XML (ou les données qu’il contient) provient du code partiellement approuvé, traitez l’objet désérialisé obtenu comme des données non approuvées.
Le fait que le ExtensionDataObject type n’a aucun membre public ne signifie pas que les données qu’il contient sont sécurisées. Par exemple, si vous désérialisez à partir d’une source de données privilégiée dans un objet dans lequel certaines données résident, passez cet objet à du code partiellement approuvé, le code partiellement approuvé peut lire les données dans l’objet
ExtensionDataObjecten sérialisant l’objet. Envisagez de définir IgnoreExtensionDataObject surtruelors de la désérialisation à partir d'une source de données privilégiée vers un objet qui sera ensuite transmis à du code partiellement fiable.DataContractSerializer et DataContractJsonSerializer prennent en charge la sérialisation de membres privés, protégés, internes et publics en mode de confiance totale. Toutefois, en mode de confiance partielle, seuls les membres publics peuvent être sérialisés. Une SecurityException est levée si une application tente de sérialiser un membre qui n'est pas public.
Pour autoriser la sérialisation de membres internes ou protégés en mode de confiance partielle, utilisez l'attribut d'assembly InternalsVisibleToAttribute . Cet attribut permet à un assembly de déclarer que ses membres internes sont visibles à certains autres assemblys. Dans ce cas, un assembly qui souhaite sérialiser ses membres internes déclare que ces derniers sont visibles à System.Runtime.Serialization.dll.
L’avantage de cette approche est qu’elle ne nécessite pas de chemin de génération de code élevé.
En même temps, il y a deux inconvénients majeurs.
Le premier étant que la propriété de sélection de l'attribut InternalsVisibleToAttribute est au niveau de l'assembly. Autrement dit, vous ne pouvez pas spécifier que seule une certaine classe peut avoir ses membres internes sérialisés. Bien sûr, vous pouvez toujours choisir de ne pas sérialiser un membre interne spécifique, en n’ajoutant simplement pas d’attribut DataMemberAttribute à ce membre. De même, un développeur peut également choisir de rendre un membre interne plutôt que privé ou protégé, avec de légères préoccupations de visibilité.
Le deuxième inconvénient est qu’il ne prend toujours pas en charge les membres privés ou protégés.
Pour illustrer l’utilisation de l’attribut InternalsVisibleToAttribute en confiance partielle, tenez compte du programme suivant :
public class Program { public static void Main(string[] args) { try { // PermissionsHelper.InternetZone corresponds to the PermissionSet for partial trust. // PermissionsHelper.InternetZone.PermitOnly(); MemoryStream memoryStream = new MemoryStream(); new DataContractSerializer(typeof(DataNode)). WriteObject(memoryStream, new DataNode()); } finally { CodeAccessPermission.RevertPermitOnly(); } } [DataContract] public class DataNode { [DataMember] internal string Value = "Default"; } }Dans l’exemple ci-dessus,
PermissionsHelper.InternetZonecorrespond à la PermissionSet confiance partielle. Maintenant, sans l’attribut InternalsVisibleToAttribute, l’application échouera, lançant une exception SecurityException indiquant que les membres non publics ne peuvent pas être sérialisés dans un environnement de confiance partielle.Toutefois, si nous ajoutons la ligne suivante au fichier source, le programme s’exécute correctement.
[assembly:System.Runtime.CompilerServices.InternalsVisibleTo("System.Runtime.Serialization, PublicKey = 00000000000000000400000000000000")]
Autres problèmes de gestion de l’état
Quelques autres préoccupations concernant la gestion de l’état des objets méritent d’être mentionnées :
Lorsque vous utilisez le modèle de programmation basé sur le flux avec un transport de diffusion en continu, le traitement du message se produit à mesure que le message arrive. L’expéditeur du message peut abandonner l’opération d’envoi au milieu du flux, laissant votre code dans un état imprévisible si un plus grand nombre de contenu était attendu. En général, ne comptez pas sur l'exhaustivité du flux et n'exécutez rien dans une opération basée sur le flux qui ne puisse pas être restauré au cas où le flux de données serait abandonné. Cela s’applique également à la situation où un message peut être mal formé après le corps du streaming (par exemple, il peut manquer une balise de fin pour l’enveloppe SOAP ou avoir un deuxième corps de message).
L’utilisation de la
IExtensibleDataObjectfonctionnalité peut entraîner l’émission de données sensibles. Si vous acceptez des données d'une source non fiable dans des contrats de données avecIExtensibleObjectData, puis vous les émettez de nouveau sur un canal sécurisé où les messages sont signés, vous vous portez potentiellement garant de données dont vous ne savez rien. De plus, l’état global que vous envoyez peut ne pas être valide si vous prenez en compte les données connues et inconnues. Évitez cette situation en définissant sélectivement la propriéténullde données d’extension ou en désactivant sélectivement la fonctionnalitéIExtensibleObjectData.
Importation de schéma
Normalement, le processus d’importation de schéma pour générer des types se produit uniquement au moment de la conception, par exemple lors de l’utilisation de l’outil utilitaire de métadonnées ServiceModel (Svcutil.exe) sur un service Web pour générer une classe cliente. Toutefois, dans des scénarios plus avancés, vous pouvez traiter le schéma au moment de l’exécution. Sachez que cela peut vous exposer à des risques de déni de service. Certains schémas peuvent prendre beaucoup de temps à être importés. N’utilisez jamais le XmlSerializer composant d’importation de schéma dans de tels scénarios si les schémas proviennent éventuellement d’une source non approuvée.
Menaces spécifiques à l’intégration ASP.NET AJAX
Lorsque l’utilisateur implémente WebScriptEnablingBehavior ou WebHttpBehavior, WCF expose un point de terminaison qui peut accepter des messages XML et JSON. Toutefois, il n’existe qu’un seul ensemble de quotas de lecteur, utilisé à la fois par le lecteur XML et le lecteur JSON. Certains paramètres de quota peuvent être appropriés pour un lecteur, mais trop volumineux pour l’autre.
Lors de l’implémentation WebScriptEnablingBehavior, l’utilisateur a la possibilité d’exposer un proxy JavaScript au niveau du point de terminaison. Les problèmes de sécurité suivants doivent être pris en compte :
Des informations sur le service (noms d’opérations, noms de paramètres, et ainsi de suite) peuvent être obtenues en examinant le proxy JavaScript.
Lorsque vous utilisez le point de terminaison JavaScript, les informations sensibles et privées peuvent être conservées dans le cache du navigateur web client.
Remarque sur les composants
WCF est un système flexible et personnalisable. La plupart du contenu de cette rubrique se concentrent sur les scénarios d’utilisation WCF les plus courants. Toutefois, il est possible de composer des composants WCF de plusieurs façons différentes. Il est important de comprendre les implications de sécurité de l’utilisation de chaque composant. En particulier:
Lorsque vous devez utiliser des lecteurs XML, utilisez les lecteurs que la XmlDictionaryReader classe fournit par opposition à d’autres lecteurs. Les lecteurs sécurisés sont créés à l'aide des méthodes CreateTextReader, CreateBinaryReader ou CreateMtomReader. N’utilisez pas la Create méthode. Configurez toujours les lecteurs avec des quotas sécurisés. Les moteurs de sérialisation dans WCF sont sécurisés uniquement lorsqu’ils sont utilisés avec des lecteurs XML sécurisés à partir de WCF.
Lorsque vous utilisez l’option DataContractSerializer pour désérialiser des données potentiellement non approuvées, définissez toujours la MaxItemsInObjectGraph propriété.
Lors de la création d’un message, définissez le
maxSizeOfHeadersparamètre s’ilMaxReceivedMessageSizen’offre pas suffisamment de protection.Lors de la création d’un encodeur, configurez toujours les quotas appropriés, tels que
MaxSessionSizeetMaxBufferSize.Lorsque vous utilisez un filtre de message XPath, définissez la NodeQuota valeur pour limiter la quantité de nœuds XML que le filtre visite. N’utilisez pas d’expressions XPath qui peuvent prendre beaucoup de temps pour calculer sans visiter de nombreux nœuds.
En général, lors de l’utilisation d’un composant qui accepte un quota, comprenez ses implications en matière de sécurité et définissez-le sur une valeur sûre.