Beveiligingsoverwegingen voor gegevens
Bij het omgaan met gegevens in Windows Communication Foundation (WCF) moet u rekening houden met een aantal bedreigingscategorieën. De volgende lijst bevat de belangrijkste bedreigingsklassen die betrekking hebben op gegevensverwerking. WCF biedt hulpprogramma's om deze bedreigingen te beperken.
Denial of Service
Bij het ontvangen van niet-vertrouwde gegevens kunnen de gegevens ertoe leiden dat de ontvangende zijde toegang heeft tot een onevenredige hoeveelheid verschillende resources, zoals geheugen, threads, beschikbare verbindingen of processorcycli door langdurige berekeningen te veroorzaken. Een denial-of-service-aanval op een server kan ertoe leiden dat deze vastloopt en geen berichten van andere, legitieme clients kan verwerken.
Uitvoering van schadelijke code
Inkomende niet-vertrouwde gegevens veroorzaken dat de ontvangende zijde code uitvoert die niet van plan was.
Openbaarmaking van informatie
De externe aanvaller dwingt de ontvangende partij om te reageren op zijn verzoeken op een zodanige manier dat er meer informatie wordt vrijgegeven dan het van plan is.
Door de gebruiker verstrekte code- en codetoegangsbeveiliging
Een aantal plaatsen in de WCF-infrastructuur (Windows Communication Foundation) voert code uit die wordt geleverd door de gebruiker. De DataContractSerializer serialisatie-engine kan bijvoorbeeld door de gebruiker geleverde eigenschapstoegangsors set
en get
-accessors aanroepen. De WCF-kanaalinfrastructuur kan ook worden aangeroepen in door de gebruiker geleverde afgeleide klassen van de Message klasse.
Het is de verantwoordelijkheid van de auteur van de code om ervoor te zorgen dat er geen beveiligingsproblemen bestaan. Als u bijvoorbeeld een gegevenscontracttype maakt met een eigenschap van het gegevenslid van het type geheel getal en in de set
accessor-implementatie een matrix toewijst op basis van de eigenschapswaarde, stelt u de mogelijkheid bloot van een denial-of-service-aanval als een schadelijk bericht een extreem grote waarde voor dit gegevenslid bevat. Over het algemeen vermijdt u toewijzingen op basis van binnenkomende gegevens of langdurige verwerking in door de gebruiker verstrekte code (met name als langdurige verwerking kan worden veroorzaakt door een kleine hoeveelheid binnenkomende gegevens). Wanneer u beveiligingsanalyses uitvoert van door de gebruiker geleverde code, moet u ook rekening houden met alle foutgevallen (dat wil gezegd, alle codevertakkingen waarbij uitzonderingen worden gegenereerd).
Het ultieme voorbeeld van door de gebruiker geleverde code is de code in uw service-implementatie voor elke bewerking. De beveiliging van uw service-implementatie is uw verantwoordelijkheid. Het is eenvoudig om onbedoeld onveilige implementaties voor bewerkingen te maken die kunnen leiden tot denial-of-service-beveiligingsproblemen. Een bewerking die bijvoorbeeld een tekenreeks gebruikt en de lijst met klanten uit een database retourneert waarvan de naam begint met die tekenreeks. Als u met een grote database werkt en de tekenreeks die wordt doorgegeven slechts één letter is, kan uw code proberen een bericht te maken dat groter is dan alle beschikbare geheugen, waardoor de hele service mislukt. (Een OutOfMemoryException kan niet worden hersteld in .NET Framework en resulteert altijd in de beëindiging van uw toepassing.)
Zorg ervoor dat er geen schadelijke code is aangesloten op de verschillende uitbreidbaarheidspunten. Dit is met name relevant bij het uitvoeren onder gedeeltelijke vertrouwensrelatie, het omgaan met typen van gedeeltelijk vertrouwde assembly's of het maken van onderdelen die kunnen worden gebruikt door gedeeltelijk vertrouwde code. Zie 'Gedeeltelijke vertrouwensbedreigingen' in een latere sectie voor meer informatie.
Houd er rekening mee dat bij het uitvoeren in gedeeltelijke vertrouwensrelatie de serialisatie-infrastructuur van het gegevenscontract slechts een beperkte subset van het programmeermodel van het gegevenscontract ondersteunt. Privégegevensleden of -typen die het SerializableAttribute kenmerk gebruiken, worden bijvoorbeeld niet ondersteund. Zie Gedeeltelijke vertrouwensrelatie voor meer informatie.
Notitie
Cas (Code Access Security) is afgeschaft in alle versies van .NET Framework en .NET. Recente versies van .NET respecteren geen CAS-aantekeningen en produceren fouten als CAS-gerelateerde API's worden gebruikt. Ontwikkelaars moeten alternatieve manieren zoeken om beveiligingstaken uit te voeren.
Onbedoelde openbaarmaking van informatie voorkomen
Bij het ontwerpen van serialiseerbare typen met het oog op beveiliging is openbaarmaking van informatie een mogelijke zorg.
Overweeg het volgende:
Met DataContractSerializer het programmeermodel kunnen persoonlijke en interne gegevens buiten het type of de assembly tijdens de serialisatie worden blootgesteld. Daarnaast kan de vorm van een type worden weergegeven tijdens het exporteren van het schema. Zorg ervoor dat u de serialisatieprojectie van uw type begrijpt. Als u niets zichtbaar wilt maken, schakelt u het serialiseren uit (bijvoorbeeld door het DataMemberAttribute kenmerk niet toe te passen in het geval van een gegevenscontract).
Houd er rekening mee dat hetzelfde type meerdere serialisatieprojecties kan hebben, afhankelijk van de serialisatiefunctie die wordt gebruikt. Hetzelfde type kan één set gegevens weergeven wanneer deze wordt gebruikt met de DataContractSerializer en een andere set gegevens wanneer deze wordt gebruikt met de XmlSerializer. Per ongeluk het gebruik van de verkeerde serializer kan leiden tot openbaarmaking van informatie.
Als u de XmlSerializer verouderde remote procedure call (RPC)/gecodeerde modus gebruikt, kan de vorm van de objectgrafiek aan de verzendzijde aan de ontvangstzijde onbedoeld zichtbaar worden gemaakt.
Denial of Service-aanvallen voorkomen
Targets
Als de ontvangende zijde een aanzienlijke hoeveelheid geheugen toewijst, is een mogelijke Denial-of-Service-aanval. Hoewel deze sectie zich richt op problemen met geheugenverbruik die voortvloeien uit grote berichten, kunnen andere aanvallen optreden. Berichten kunnen bijvoorbeeld een onevenredige hoeveelheid verwerkingstijd gebruiken.
Denial-of-service-aanvallen worden meestal beperkt met behulp van quota. Wanneer een quotum wordt overschreden, wordt normaal gesproken een QuotaExceededException uitzondering gegenereerd. Zonder het quotum kan een schadelijk bericht ertoe leiden dat al het beschikbare geheugen wordt geopend, wat resulteert in een OutOfMemoryException uitzondering of dat alle beschikbare stacks worden geopend, wat resulteert in een StackOverflowException.
Het scenario dat het quotum is overschreden, kan worden hersteld; als het bericht in een actieve service wordt aangetroffen, wordt het bericht dat momenteel wordt verwerkt, verwijderd en blijft de service actief en worden verdere berichten verwerkt. De out-of-memory- en stack-overloopscenario's kunnen echter nergens in .NET Framework worden hersteld; de service wordt beëindigd als er dergelijke uitzonderingen optreden.
Quota in WCF hebben geen voorafgaande toewijzing. Als het MaxReceivedMessageSize quotum (gevonden in verschillende klassen) bijvoorbeeld is ingesteld op 128 kB, betekent dit niet dat voor elk bericht automatisch 128 kB wordt toegewezen. Het werkelijke bedrag dat is toegewezen, is afhankelijk van de werkelijke grootte van het binnenkomende bericht.
Er zijn veel quota beschikbaar op de transportlaag. Dit zijn quota die worden afgedwongen door het specifieke transportkanaal dat wordt gebruikt (HTTP, TCP, enzovoort). Hoewel in dit onderwerp enkele van deze quota worden besproken, worden deze quota uitgebreid beschreven in transportquota.
Hashtable-beveiligingsprobleem
Er bestaat een beveiligingsprobleem wanneer gegevenscontracten hashtables of verzamelingen bevatten. Het probleem treedt op als een groot aantal waarden wordt ingevoegd in een hashtabel waarbij een groot aantal van deze waarden dezelfde hash-waarde genereert. Dit kan worden gebruikt als een DOS-aanval. Dit beveiligingsprobleem kan worden beperkt door het bindingsquotum MaxReceivedMessageSize in te stellen. Zorg ervoor dat u dit quotum instelt om dergelijke aanvallen te voorkomen. Met dit quotum wordt een bovengrens voor de grootte van wcf-berichten bereikt. Vermijd bovendien het gebruik van hashtables of verzamelingen in uw gegevenscontracten.
Geheugenverbruik beperken zonder streaming
Het beveiligingsmodel rond grote berichten is afhankelijk van of streaming wordt gebruikt. In het eenvoudige, niet-gestreamde geval worden berichten gebufferd in het geheugen. Gebruik in dit geval het quotum voor de TransportBindingElement of op de door het MaxReceivedMessageSize systeem geleverde bindingen om te beschermen tegen grote berichten door de maximale berichtgrootte te beperken tot toegang. Houd er rekening mee dat een service mogelijk meerdere berichten tegelijk verwerkt. In dat geval bevinden ze zich allemaal in het geheugen. Gebruik de beperkingsfunctie om deze bedreiging te beperken.
Houd er ook rekening mee dat MaxReceivedMessageSize
er geen bovengrens wordt ingesteld voor geheugenverbruik per bericht, maar dat dit binnen een constante factor wordt beperkt. Als de MaxReceivedMessageSize
waarde bijvoorbeeld 1 MB is en er een bericht van 1 MB wordt ontvangen en vervolgens gedeserialiseerd wordt, is extra geheugen vereist om de grafiek met gedeserialiseerde objecten te bevatten, wat resulteert in het totale geheugenverbruik van meer dan 1 MB. Om deze reden vermijdt u het maken van serialiseerbare typen die kunnen leiden tot aanzienlijk geheugenverbruik zonder veel binnenkomende gegevens. Een gegevenscontract 'MyContract' met 50 optionele gegevenslidvelden en extra 100 privévelden kunnen bijvoorbeeld worden geïnstantieerd met de XML-constructie '<MyContract/>'. Deze XML resulteert in het geheugen dat wordt geopend voor 150 velden. Gegevensleden zijn standaard optioneel. Het probleem wordt samengesteld wanneer een dergelijk type deel uitmaakt van een matrix.
MaxReceivedMessageSize
alleen is niet voldoende om alle Denial-of-Service-aanvallen te voorkomen. Deserializer kan bijvoorbeeld gedwongen worden om een diep geneste objectgrafiek (een object dat een ander object bevat dat nog een object bevat, enzovoort) te deserialiseren door een binnenkomend bericht. Zowel de DataContractSerializer als de XmlSerializer aanroepmethoden op een geneste manier om dergelijke grafieken te deserialiseren. Het diep nesten van methodeaanroepen kan leiden tot een onherstelbaar StackOverflowException. Deze bedreiging wordt beperkt door het MaxDepth quotum in te stellen om het niveau van XML-nesting te beperken, zoals wordt beschreven in de sectie 'Xml veilig gebruiken' verderop in het onderwerp.
Het instellen van extra quota MaxReceivedMessageSize
is met name belangrijk bij het gebruik van binaire XML-codering. Het gebruik van binaire codering is enigszins gelijk aan compressie: een kleine groep bytes in het binnenkomende bericht kan veel gegevens vertegenwoordigen. Zelfs een bericht dat in de MaxReceivedMessageSize
limiet past, kan dus veel meer geheugen in beslag nemen in volledig uitgevouwen vorm. Als u dergelijke XML-specifieke bedreigingen wilt beperken, moeten alle XML-lezerquota correct worden ingesteld, zoals verderop in dit onderwerp wordt besproken in de sectie 'XML veilig gebruiken'.
Geheugenverbruik beperken met streaming
Bij het streamen kunt u een kleine MaxReceivedMessageSize
instelling gebruiken om te beschermen tegen denial-of-service-aanvallen. Complexere scenario's zijn echter mogelijk met streaming. Een uploadservice voor bestanden accepteert bijvoorbeeld bestanden die groter zijn dan alle beschikbare geheugen. Stel in dit geval de MaxReceivedMessageSize
waarde in op een extreem grote waarde, waarbij wordt verwacht dat er bijna geen gegevens in het geheugen worden gebufferd en dat het bericht rechtstreeks naar de schijf wordt gestreamd. Als een schadelijk bericht op een of andere manier WCF kan dwingen om gegevens te bufferen in plaats van het in dit geval te streamen, MaxReceivedMessageSize
wordt het bericht niet langer beschermd tegen het bericht dat toegang heeft tot alle beschikbare geheugen.
Om deze bedreiging te beperken, bestaan er specifieke quota-instellingen voor verschillende WCF-gegevensverwerkingsonderdelen die buffering beperken. De belangrijkste hiervan is de MaxBufferSize
eigenschap op verschillende transportbindingselementen en standaardbindingen. Bij het streamen moet dit quotum worden ingesteld, rekening houdend met de maximale hoeveelheid geheugen die u per bericht wilt toewijzen. Net als bij MaxReceivedMessageSize
de instelling wordt geen absoluut maximum voor geheugenverbruik ingesteld, maar wordt deze alleen beperkt tot binnen een constante factor. Houd ook rekening met MaxReceivedMessageSize
de mogelijkheid dat meerdere berichten tegelijk worden verwerkt.
MaxBufferSize Details
De MaxBufferSize
eigenschap beperkt alle wcf-bulkbufferings. WCF buffert bijvoorbeeld altijd SOAP-headers en SOAP-fouten, evenals eventuele MIME-onderdelen die niet in de natuurlijke leesrichting in een MTOM-bericht (Message Transmission Optimization Mechanism) zijn gevonden. Deze instelling beperkt de hoeveelheid buffering in al deze gevallen.
WCF doet dit door de MaxBufferSize
waarde door te geven aan de verschillende onderdelen die kunnen bufferen. Sommige overbelastingen van de Message klasse nemen bijvoorbeeld CreateMessage een maxSizeOfHeaders
parameter. WCF geeft de MaxBufferSize
waarde door aan deze parameter om de hoeveelheid SOAP-headerbuffering te beperken. Het is belangrijk om deze parameter in te stellen wanneer u de Message klasse rechtstreeks gebruikt. Over het algemeen is het belangrijk om bij het gebruik van een onderdeel in WCF dat quotumparameters gebruikt, inzicht te krijgen in de gevolgen van de beveiliging van deze parameters en deze correct in te stellen.
De MTOM-berichtcoderingsprogramma heeft ook een MaxBufferSize
instelling. Wanneer u standaardbindingen gebruikt, wordt dit automatisch ingesteld op de waarde op transportniveau MaxBufferSize
. Wanneer u echter het bindingselement van het MTOM-berichtcoderingsprogramma gebruikt om een aangepaste binding te maken, is het belangrijk om de MaxBufferSize
eigenschap in te stellen op een veilige waarde wanneer streaming wordt gebruikt.
Streamingaanvallen op basis van XML
MaxBufferSize
alleen is niet voldoende om ervoor te zorgen dat WCF niet kan worden gedwongen tot buffering wanneer streaming wordt verwacht. De WCF XML-lezers bufferen bijvoorbeeld altijd de hele tag voor het starten van het XML-element bij het lezen van een nieuw element. Dit wordt gedaan zodat naamruimten en kenmerken correct worden verwerkt. Als MaxReceivedMessageSize
deze is geconfigureerd om groot te zijn (bijvoorbeeld om een scenario voor het streamen van grote bestanden van direct naar schijf mogelijk te maken), kan er een schadelijk bericht worden samengesteld waarbij de hele berichttekst een grote XML-element starttag is. Een poging om het te lezen resulteert in een OutOfMemoryException. Dit is een van de vele mogelijke denial-of-service-aanvallen op basis van XML die allemaal kunnen worden beperkt met behulp van XML-lezerquota, die verderop in dit onderwerp worden besproken in de sectie 'XML veilig gebruiken'. Bij het streamen is het vooral belangrijk om al deze quota in te stellen.
Programmeermodellen voor streaming en buffering combineren
Veel mogelijke aanvallen ontstaan door het combineren van streaming- en niet-streaming programmeermodellen in dezelfde service. Stel dat er een servicecontract is met twee bewerkingen: één gebruikt een Stream en een andere een matrix van een aangepast type. Stel ook dat deze MaxReceivedMessageSize
is ingesteld op een grote waarde om de eerste bewerking in staat te stellen grote stromen te verwerken. Helaas betekent dit dat grote berichten ook naar de tweede bewerking kunnen worden verzonden en dat de deserializer gegevens in het geheugen buffert als een matrix voordat de bewerking wordt aangeroepen. Dit is een mogelijke denial-of-service-aanval: het MaxBufferSize
quotum beperkt niet de grootte van de berichttekst, wat de deserializer gebruikt.
Vermijd daarom het combineren van stream- en niet-gestreamde bewerkingen in hetzelfde contract. Als u de twee programmeermodellen absoluut moet combineren, gebruikt u de volgende voorzorgsmaatregelen:
Schakel de IExtensibleDataObject functie uit door de IgnoreExtensionDataObject eigenschap van de ServiceBehaviorAttribute eigenschap in te stellen op
true
. Dit zorgt ervoor dat alleen leden die deel uitmaken van het contract, gedeserialiseerd worden.Stel de MaxItemsInObjectGraph eigenschap van de DataContractSerializer eigenschap in op een veilige waarde. Dit quotum is ook beschikbaar voor het ServiceBehaviorAttribute kenmerk of via de configuratie. Dit quotum beperkt het aantal objecten dat wordt gedeserialiseerd in één deserialisatie-aflevering. Normaal gesproken wordt elke bewerkingsparameter of het hoofdgedeelte van een bericht in een berichtcontract gedeserialiseerd in één aflevering. Bij het deserialiseren van matrices wordt elke matrixvermelding geteld als een afzonderlijk object.
Stel alle XML-lezerquota in op veilige waarden. Let op MaxDepth, MaxStringContentLengthen MaxArrayLength vermijd tekenreeksen in niet-streamingbewerkingen.
Bekijk de lijst met bekende typen en houd er rekening mee dat een van deze typen op elk gewenst moment kan worden geïnstantieerd (zie de sectie 'Voorkomen dat onbedoelde typen worden geladen' verderop in dit onderwerp).
Gebruik geen typen die de IXmlSerializable interface implementeren die veel gegevens bufferen. Voeg dergelijke typen niet toe aan de lijst met bekende typen.
Gebruik geen XmlElementmatrices XmlNode , Byte matrices of typen die in een contract worden geïmplementeerd ISerializable .
Gebruik de XmlElement, XmlNode matrices, Byte matrices of typen die in de lijst met bekende typen worden geïmplementeerd ISerializable niet.
De voorgaande voorzorgsmaatregelen zijn van toepassing wanneer de niet-gestreamde bewerking gebruikmaakt van de DataContractSerializer. Combineer nooit streaming- en niet-streamingprogrammeermodellen op dezelfde service als u de XmlSerializer, omdat deze niet over de beveiliging van het MaxItemsInObjectGraph quotum beschikt.
Slow Stream-aanvallen
Een klasse streaming denial-of-service-aanvallen omvat geen geheugenverbruik. In plaats daarvan omvat de aanval een trage afzender of ontvanger van gegevens. Terwijl u wacht tot de gegevens zijn verzonden of ontvangen, worden resources zoals threads en beschikbare verbindingen uitgeput. Deze situatie kan zich voordoen als gevolg van een kwaadwillende aanval of van een legitieme afzender/ontvanger op een trage netwerkverbinding.
Als u deze aanvallen wilt beperken, stelt u de transporttime-outs correct in. Zie Transportquota voor meer informatie. Ten tweede gebruikt u nooit synchrone Read
bewerkingen Write
wanneer u werkt met streams in WCF.
XML veilig gebruiken
Notitie
Hoewel deze sectie over XML gaat, is de informatie ook van toepassing op JSON-documenten (JavaScript Object Notation). De quota werken op dezelfde manier, met behulp van toewijzing tussen JSON en XML.
Beveiligde XML-lezers
De XML-infoset vormt de basis van alle berichtverwerking in WCF. Wanneer u XML-gegevens accepteert van een niet-vertrouwde bron, zijn er een aantal denial-of-service-aanvalsmogelijkheden die moeten worden beperkt. WCF biedt speciale, beveiligde XML-lezers. Deze lezers worden automatisch gemaakt bij gebruik van een van de standaardcoderingen in WCF (tekst, binair of MTOM).
Sommige beveiligingsfuncties voor deze lezers zijn altijd actief. De lezers verwerken bijvoorbeeld nooit DTD's (documenttypedefinities), die een mogelijke bron zijn van denial-of-service-aanvallen en mogen nooit worden weergegeven in legitieme SOAP-berichten. Andere beveiligingsfuncties omvatten lezerquota die moeten worden geconfigureerd, die worden beschreven in de volgende sectie.
Wanneer u rechtstreeks met XML-lezers werkt (zoals bij het schrijven van uw eigen aangepaste encoder of wanneer u rechtstreeks met de Message klasse werkt), gebruikt u altijd de WCF-beveiligde lezers wanneer er een kans is om met niet-vertrouwde gegevens te werken. Maak de beveiligde lezers door een van de statische factory-methode-overbelastingen van CreateTextReader, CreateBinaryReaderof CreateMtomReader in de XmlDictionaryReader klasse aan te roepen. Wanneer u een lezer maakt, geeft u veilige quotumwaarden door. Roep de overbelasting van de Create
methode niet aan. Hiermee wordt geen WCF-lezer gemaakt. In plaats daarvan wordt een lezer gemaakt die niet wordt beveiligd door de beveiligingsfuncties die in deze sectie worden beschreven.
Quota voor lezer
De beveiligde XML-lezers hebben vijf configureerbare quota. Deze worden normaal gesproken geconfigureerd met behulp van de ReaderQuotas
eigenschap voor de coderingsbindingselementen of standaardbindingen, of door een XmlDictionaryReaderQuotas object te gebruiken dat wordt doorgegeven bij het maken van een lezer.
MaxBytesPerRead
Dit quotum beperkt het aantal bytes dat in één Read
bewerking wordt gelezen bij het lezen van de tag start van het element en de bijbehorende kenmerken. (In niet-gestreamde gevallen wordt de elementnaam zelf niet meegeteld voor het quotum.) MaxBytesPerRead is om de volgende redenen belangrijk:
De elementnaam en de bijbehorende kenmerken worden altijd gebufferd in het geheugen wanneer ze worden gelezen. Daarom is het belangrijk om dit quotum correct in te stellen in de streamingmodus om overmatige buffering te voorkomen wanneer streaming wordt verwacht. Zie het
MaxDepth
quotumgedeelte voor informatie over de werkelijke hoeveelheid buffering die plaatsvindt.Het gebruik van te veel XML-kenmerken kan onevenredige verwerkingstijd in gebruik hebben, omdat kenmerknamen moeten worden gecontroleerd op uniekheid.
MaxBytesPerRead
vermindert deze bedreiging.
MaxDepth
Dit quotum beperkt de maximale nestdiepte van XML-elementen. Het document '<A><B><C/><B/B></A>' heeft bijvoorbeeld een nestdiepte van drie. MaxDepth is om de volgende redenen belangrijk:
MaxDepth
communiceert metMaxBytesPerRead
: de lezer bewaart altijd gegevens in het geheugen voor het huidige element en alle bovenliggende elementen, zodat het maximale geheugenverbruik van de lezer evenredig is met het product van deze twee instellingen.Wanneer deserialiseren van een diep geneste objectgrafiek, wordt de deserializer gedwongen toegang te krijgen tot de hele stack en een onherstelbaar StackOverflowExceptionte gooien. Er bestaat een directe correlatie tussen XML-nesting en object genest voor zowel de DataContractSerializer als de XmlSerializer. Gebruik
MaxDepth
dit om deze bedreiging te beperken.
MaxNameTableCharCount
Dit quotum beperkt de grootte van de naamtabel van de lezer. De naamtabel bevat bepaalde tekenreeksen (zoals naamruimten en voorvoegsels) die worden aangetroffen bij het verwerken van een XML-document. Omdat deze tekenreeksen in het geheugen worden gebufferd, stelt u dit quotum in om overmatige buffering te voorkomen wanneer streaming wordt verwacht.
MaxStringContentLength
Dit quotum beperkt de maximale tekenreeksgrootte die de XML-lezer retourneert. Dit quotum beperkt het geheugenverbruik niet in de XML-lezer zelf, maar in het onderdeel dat de lezer gebruikt. Als de DataContractSerializer gebruiker bijvoorbeeld een lezer gebruikt die is beveiligd met MaxStringContentLength, worden tekenreeksen die groter zijn dan dit quotum niet gedeserialiseerd. Wanneer u de XmlDictionaryReader klasse rechtstreeks gebruikt, respecteren niet alle methoden dit quotum, maar alleen de methoden die specifiek zijn ontworpen voor het lezen van tekenreeksen, zoals de ReadContentAsString methode. De Value eigenschap voor de lezer wordt niet beïnvloed door dit quotum en mag dus niet worden gebruikt wanneer de beveiliging van dit quotum noodzakelijk is.
MaxArrayLength
Dit quotum beperkt de maximale grootte van een matrix met primitieven die de XML-lezer retourneert, inclusief bytematrices. Dit quotum beperkt het geheugenverbruik in de XML-lezer zelf niet, maar in elk onderdeel dat de lezer gebruikt. Wanneer de DataContractSerializer gebruiker bijvoorbeeld een lezer gebruikt die is beveiligd met MaxArrayLength, wordt bytematrices die groter zijn dan dit quotum, niet gedeserialiseerd. Het is belangrijk om dit quotum in te stellen bij het combineren van streaming- en bufferprogrammeermodellen in één contract. Houd er rekening mee dat wanneer u de XmlDictionaryReader klasse rechtstreeks gebruikt, alleen de methoden die specifiek zijn ontworpen om matrices van willekeurige grootte van bepaalde primitieve typen te lezen, zoals ReadInt32Arraydit quotum respecteren.
Bedreigingen die specifiek zijn voor binaire codering
De binaire XML-coderings-WCF ondersteunt een functie voor woordenlijsttekenreeksen . Een grote tekenreeks kan worden gecodeerd met slechts een paar bytes. Dit maakt aanzienlijke prestatieverbeteringen mogelijk, maar introduceert nieuwe denial-of-service-bedreigingen die moeten worden beperkt.
Er zijn twee soorten woordenlijsten: statisch en dynamisch. De statische woordenlijst is een ingebouwde lijst met lange tekenreeksen die kunnen worden weergegeven met behulp van een korte code in de binaire codering. Deze lijst met tekenreeksen is opgelost wanneer de lezer wordt gemaakt en niet kan worden gewijzigd. Geen van de tekenreeksen in de statische woordenlijst die WCF standaard gebruikt, is voldoende groot om een ernstige denial-of-service-bedreiging te vormen, hoewel deze mogelijk nog steeds worden gebruikt bij een aanval op woordenlijstuitbreiding. In geavanceerde scenario's waarin u uw eigen statische woordenlijst opgeeft, moet u voorzichtig zijn bij het introduceren van grote woordenlijsttekenreeksen.
Met de functie dynamische woordenlijsten kunnen berichten hun eigen tekenreeksen definiëren en deze koppelen aan korte codes. Deze tekenreeks-naar-codetoewijzingen worden tijdens de hele communicatiesessie in het geheugen bewaard, zodat volgende berichten de tekenreeksen niet opnieuw hoeven te verzenden en codes kunnen gebruiken die al zijn gedefinieerd. Deze tekenreeksen kunnen van willekeurige lengte zijn en vormen dus een ernstigere bedreiging dan die in de statische woordenlijst.
De eerste bedreiging die moet worden beperkt, is de mogelijkheid dat de dynamische woordenlijst (de tabel voor het toewijzen van tekenreeks-naar-code) te groot wordt. Deze woordenlijst kan worden uitgebreid in de loop van verschillende berichten, waardoor het quotum geen beveiliging biedt, omdat deze MaxReceivedMessageSize
alleen van toepassing is op elk bericht afzonderlijk. Daarom bestaat er een afzonderlijke MaxSessionSize eigenschap op de BinaryMessageEncodingBindingElement eigenschap die de grootte van de woordenlijst beperkt.
In tegenstelling tot de meeste andere quota is dit quotum ook van toepassing bij het schrijven van berichten. Als het bericht wordt overschreden bij het lezen van een bericht, wordt het QuotaExceededException
zoals gebruikelijk gegenereerd. Als deze wordt overschreden bij het schrijven van een bericht, worden tekenreeksen die ervoor zorgen dat het quotum wordt overschreden, als zodanig geschreven zonder de functie voor dynamische woordenlijsten te gebruiken.
Bedreigingen voor woordenlijstuitbreiding
Een belangrijke klasse van binaire specifieke aanvallen komt voort uit woordenlijstuitbreiding. Een klein bericht in binaire vorm kan worden omgezet in een zeer groot bericht in volledig uitgevouwen tekstuele vorm als het uitgebreid gebruikmaakt van de functie tekenreekswoordenlijsten. De uitbreidingsfactor voor dynamische woordenlijsttekenreeksen wordt beperkt door het MaxSessionSize quotum, omdat geen dynamische woordenlijsttekenreeks de maximale grootte van de hele woordenlijst overschrijdt.
De MaxNameTableCharCount, MaxStringContentLength
en MaxArrayLength
eigenschappen beperken alleen het geheugenverbruik. Ze zijn normaal gesproken niet vereist om bedreigingen in het niet-gestreamde gebruik te beperken, omdat het geheugengebruik al wordt beperkt door MaxReceivedMessageSize
. MaxReceivedMessageSize
Telt echter bytes vóór uitbreiding. Wanneer binaire codering in gebruik is, kan het geheugenverbruik mogelijk verder MaxReceivedMessageSize
gaan dan , alleen beperkt door een factor van MaxSessionSize. Daarom is het belangrijk dat u altijd alle quota van lezers (met name MaxStringContentLength) instelt bij het gebruik van de binaire codering.
Wanneer u binaire codering samen met de DataContractSerializercode gebruikt, kan de IExtensibleDataObject
interface worden misbruikt om een aanval op woordenlijstuitbreiding te koppelen. Deze interface biedt in wezen onbeperkte opslag voor willekeurige gegevens die geen deel uitmaken van het contract. Als quota niet laag genoeg kunnen worden ingesteld, MaxSessionSize
zodat vermenigvuldigd met MaxReceivedMessageSize
geen probleem is, schakelt u de functie uit bij het IExtensibleDataObject
gebruik van de binaire codering. Stel de IgnoreExtensionDataObject
eigenschap in true
op het ServiceBehaviorAttribute
kenmerk. U kunt de IExtensibleDataObject
interface ook niet implementeren. Zie Forward-Compatible Data Contracts voor meer informatie.
Samenvatting van quota
De volgende tabel bevat een overzicht van de richtlijnen voor quota.
Conditie | Belangrijke quota die moeten worden ingesteld |
---|---|
Geen streaming of streaming kleine berichten, tekst of MTOM-codering | MaxReceivedMessageSize , en MaxBytesPerRead MaxDepth |
Geen streaming of streaming kleine berichten, binaire codering | MaxReceivedMessageSize , MaxSessionSize en alle ReaderQuotas |
Grote berichten, tekst of MTOM-codering streamen | MaxBufferSize en alle ReaderQuotas |
Grote berichten streamen, binaire codering | MaxBufferSize , MaxSessionSize en alle ReaderQuotas |
Time-outs op transportniveau moeten altijd worden ingesteld en nooit synchrone lees-/schrijfbewerkingen gebruiken wanneer streaming wordt gebruikt, ongeacht of u grote of kleine berichten streamt.
Als u twijfelt over een quotum, stelt u deze in op een veilige waarde in plaats van het open te laten.
Uitvoering van schadelijke code voorkomen
De volgende algemene klassen bedreigingen kunnen code uitvoeren en onbedoelde effecten hebben:
De deserializer laadt een schadelijk, onveilig of beveiligingsgevoelig type.
Een binnenkomend bericht zorgt ervoor dat de deserializer een exemplaar van een normaal veilig type maakt op een zodanige manier dat het onbedoelde gevolgen heeft.
In de volgende secties worden deze klassen bedreigingen verder besproken.
DataContractSerializer
(Zie de relevante documentatie voor informatie over de XmlSerializerbeveiliging.) Het beveiligingsmodel voor het XmlSerializer model is vergelijkbaar met dat van de DataContractSerializer, en verschilt meestal in details. Het kenmerk wordt bijvoorbeeld XmlIncludeAttribute gebruikt voor het opnemen van het type in plaats van het KnownTypeAttribute kenmerk. Sommige bedreigingen die uniek zijn voor de XmlSerializer bedreigingen worden echter verderop in dit onderwerp besproken.
Voorkomen dat onbedoelde typen worden geladen
Het laden van onbedoelde typen kan aanzienlijke gevolgen hebben, ongeacht of het type schadelijk is of alleen beveiligingsgevoelige bijwerkingen heeft. Een type kan misbruikbare beveiligingsproblemen bevatten, beveiligingsgevoelige acties uitvoeren in de constructor of klasseconstructor, een grote geheugenvoetafdruk hebben die denial-of-service-aanvallen faciliteert of niet-herstelbare uitzonderingen kan veroorzaken. Typen kunnen klasseconstructors hebben die worden uitgevoerd zodra het type wordt geladen en voordat er exemplaren worden gemaakt. Om deze redenen is het belangrijk om de set typen te beheren die de deserializer kan laden.
De DataContractSerializer deserializeert op een losjes gekoppelde manier. Het leest nooit common language runtime (CLR) type en assembly-namen van de binnenkomende gegevens. Dit is vergelijkbaar met het gedrag van de XmlSerializer, maar verschilt van het gedrag van , NetDataContractSerializerBinaryFormatteren het SoapFormatter. Losse koppeling introduceert een mate van veiligheid, omdat de externe aanvaller niet kan aangeven dat een willekeurig type alleen moet worden geladen door dat type in het bericht een naam te geven.
Het DataContractSerializer is altijd toegestaan om een type te laden dat momenteel volgens het contract wordt verwacht. Als een gegevenscontract bijvoorbeeld een gegevenslid van het type Customer
heeft, kan het DataContractSerializerCustomer
type worden geladen wanneer dit gegevenslid wordt gedeserialiseerd.
Daarnaast ondersteunt het DataContractSerializer polymorfisme. Een gegevenslid kan worden gedeclareerd als Object, maar de binnenkomende gegevens kunnen een Customer
exemplaar bevatten. Dit is alleen mogelijk als het Customer
type via een van deze mechanismen "bekend" is gemaakt aan de deserializer:
KnownTypeAttribute kenmerk toegepast op een type.
KnownTypeAttribute
kenmerk waarmee een methode wordt opgegeven die een lijst met typen retourneert.ServiceKnownTypeAttribute
kenmerk.De
KnownTypes
configuratiesectie.Een lijst met bekende typen die expliciet tijdens de DataContractSerializer bouw worden doorgegeven, als de serializer rechtstreeks wordt gebruikt.
Elk van deze mechanismen verhoogt het oppervlak door meer typen te introduceren die deserializer kan laden. Beheer elk van deze mechanismen om ervoor te zorgen dat er geen schadelijke of onbedoelde typen worden toegevoegd aan de lijst met bekende typen.
Zodra een bekend type binnen het bereik valt, kan het op elk gewenst moment worden geladen en kunnen exemplaren van het type worden gemaakt, zelfs als het contract het daadwerkelijk gebruikt. Stel dat het type 'MyDangerousType' wordt toegevoegd aan de lijst met bekende typen met behulp van een van de bovenstaande mechanismen. Dit betekent het volgende:
MyDangerousType
wordt geladen en de klasseconstructor wordt uitgevoerd.Zelfs wanneer een gegevenscontract met een tekenreeksgegevenslid wordt gedeserialiseerd, kan een schadelijk bericht nog steeds leiden tot een exemplaar van
MyDangerousType
het maken. Code inMyDangerousType
, zoals eigenschapssetters, kan worden uitgevoerd. Nadat dit is gebeurd, probeert de deserializer dit exemplaar toe te wijzen aan het gegevenslid van de tekenreeks en mislukt met een uitzondering.
Wanneer u een methode schrijft die een lijst met bekende typen retourneert of wanneer u een lijst rechtstreeks doorgeeft aan de DataContractSerializer constructor, moet u ervoor zorgen dat de code die de lijst voorbereidt, veilig is en alleen werkt op vertrouwde gegevens.
Als u bekende typen in de configuratie opgeeft, moet u ervoor zorgen dat het configuratiebestand veilig is. Gebruik altijd sterke namen in de configuratie (door de openbare sleutel van de ondertekende assembly op te geven waarin het type zich bevindt), maar geef niet de versie op van het type dat moet worden geladen. Het type laadprogramma kiest automatisch de nieuwste versie, indien mogelijk. Als u een bepaalde versie in de configuratie opgeeft, loopt u het volgende risico: een type heeft mogelijk een beveiligingsprobleem dat in een toekomstige versie kan worden opgelost, maar de kwetsbare versie wordt nog steeds geladen omdat deze expliciet is opgegeven in de configuratie.
Het hebben van te veel bekende typen heeft een ander gevolg: de DataContractSerializer cache van serialisatie-/deserialisatiecode in het toepassingsdomein wordt gemaakt, met een vermelding voor elk type dat het moet serialiseren en deserialiseren. Deze cache wordt nooit gewist zolang het toepassingsdomein wordt uitgevoerd. Daarom kan een aanvaller die zich ervan bewust is dat een toepassing veel bekende typen gebruikt, deserialisatie van al deze typen veroorzaken, waardoor de cache een onevenredig grote hoeveelheid geheugen verbruikt.
Voorkomen dat typen een onbedoelde status hebben
Een type kan interne consistentiebeperkingen hebben die moeten worden afgedwongen. Zorg ervoor dat deze beperkingen tijdens de deserialisatie niet worden onderbroken.
Het volgende voorbeeld van een type vertegenwoordigt de toestand van een luchtslot op een ruimtevaartuig en dwingt de beperking af dat zowel de binnenste als de buitendeuren niet tegelijkertijd kunnen worden geopend.
[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
Een aanvaller kan een schadelijk bericht zoals dit verzenden, de beperkingen omzeilen en het object in een ongeldige status krijgen, wat onbedoelde en onvoorspelbare gevolgen kan hebben.
<SpaceStationAirlock>
<innerDoorOpen>true</innerDoorOpen>
<outerDoorOpen>true</outerDoorOpen>
</SpaceStationAirlock>
Deze situatie kan worden vermeden door op de hoogte te zijn van de volgende punten:
Wanneer de DataContractSerializer meeste klassen worden gedeserialiseerd, worden constructors niet uitgevoerd. Vertrouw daarom niet op statusbeheer dat in de constructor wordt uitgevoerd.
Gebruik callbacks om ervoor te zorgen dat het object een geldige status heeft. De callback die is gemarkeerd met het OnDeserializedAttribute kenmerk is vooral handig omdat deze wordt uitgevoerd nadat deserialisatie is voltooid en de kans heeft om de algehele status te onderzoeken en te corrigeren. Zie Callbacks voor versietolerante serialisatie voor meer informatie.
Ontwerp geen gegevenscontracttypen om te vertrouwen op een bepaalde volgorde waarin eigenschapssetters moeten worden aangeroepen.
Zorg ervoor dat u verouderde typen gebruikt die zijn gemarkeerd met het SerializableAttribute kenmerk. Veel van deze zijn ontworpen om te werken met externe communicatie van .NET Framework voor gebruik met alleen vertrouwde gegevens. Bestaande typen die met dit kenmerk zijn gemarkeerd, zijn mogelijk niet ontworpen met de statusveiligheid.
Vertrouw niet op de IsRequired eigenschap van het DataMemberAttribute kenmerk om de aanwezigheid van gegevens op het gebied van staatsveiligheid te garanderen. Gegevens kunnen altijd
null
,zero
ofinvalid
.Vertrouw nooit een objectgrafiek die is gedeserialiseerd vanuit een niet-vertrouwde gegevensbron zonder deze eerst te valideren. Elk afzonderlijk object heeft mogelijk een consistente status, maar de objectgrafiek als geheel is mogelijk niet. Zelfs als de opslagmodus van de objectgrafiek is uitgeschakeld, kan de gedeserialiseerde grafiek meerdere verwijzingen naar hetzelfde object hebben of kringverwijzingen hebben. Zie Serialisatie en deserialisatie voor meer informatie.
NetDataContractSerializer veilig gebruiken
Het NetDataContractSerializer is een serialisatie-engine die gebruikmaakt van strakke koppeling naar typen. Dit is vergelijkbaar met de BinaryFormatter en de SoapFormatter. Dat wil gezegd, het bepaalt welk type moet worden geïnstitueerd door de .NET Framework-assembly te lezen en de naam van de binnenkomende gegevens te typen. Hoewel het deel uitmaakt van WCF, is er geen manier om deze serialisatie-engine aan te sluiten; aangepaste code moet worden geschreven. Het NetDataContractSerializer
is voornamelijk bedoeld om de migratie van externe communicatie van .NET Framework naar WCF te vereenvoudigen. Zie de relevante sectie in Serialisatie en deserialisatie voor meer informatie.
Omdat het bericht zelf kan aangeven dat elk type kan worden geladen, is het NetDataContractSerializer mechanisme inherent onveilig en mag het alleen worden gebruikt met vertrouwde gegevens. Zie de beveiligingshandleiding binaryFormatter voor meer informatie.
Zelfs wanneer deze worden gebruikt met vertrouwde gegevens, kunnen de binnenkomende gegevens onvoldoende het type opgeven dat moet worden geladen, met name als de AssemblyFormat eigenschap is ingesteld op Simple. Iedereen met toegang tot de map van de toepassing of de globale assemblycache kan een schadelijk type vervangen door het type dat moet worden geladen. Zorg altijd voor de beveiliging van de map van uw toepassing en van de globale assemblycache door machtigingen correct in te stellen.
Als u gedeeltelijk vertrouwde codetoegang tot uw NetDataContractSerializer
exemplaar toestaat of op een andere manier de surrogaatkiezer () of de serialisatiebinding (ISurrogateSelector) beheert,SerializationBinder kan de code veel controle uitoefenen over het serialisatie-/deserialisatieproces. Het kan bijvoorbeeld willekeurige typen injecteren, leiden tot openbaarmaking van informatie, manipulatie met de resulterende objectgrafiek of geserialiseerde gegevens, of de resulterende geserialiseerde stroom overlopen.
Een ander beveiligingsprobleem met de NetDataContractSerializer
service is een denial of service, geen bedreiging voor het uitvoeren van schadelijke code. Wanneer u het NetDataContractSerializer
quotum gebruikt, stelt u het MaxItemsInObjectGraph quotum altijd in op een veilige waarde. Het is eenvoudig om een klein schadelijk bericht te maken dat een matrix met objecten toewijst waarvan de grootte alleen wordt beperkt door dit quotum.
XmlSerializer-specifieke bedreigingen
Het XmlSerializer beveiligingsmodel is vergelijkbaar met dat van de DataContractSerializer. Een paar bedreigingen zijn echter uniek voor de XmlSerializer.
De XmlSerializer genereert serialisatieassembly's tijdens runtime die code bevatten die daadwerkelijk serialiseren en deserialisaties bevatten. Deze assembly's worden gemaakt in een tijdelijke map met bestanden. Als een ander proces of een andere gebruiker toegangsrechten voor die map heeft, kan deze de serialisatie-/deserialisatiecode overschrijven met willekeurige code. Vervolgens XmlSerializer wordt deze code uitgevoerd met behulp van de beveiligingscontext, in plaats van de serialisatie-/deserialisatiecode. Zorg ervoor dat de machtigingen juist zijn ingesteld in de map met tijdelijke bestanden om te voorkomen dat dit gebeurt.
De XmlSerializer modus heeft ook een modus waarin vooraf gegenereerde serialisatieassembly's worden gebruikt in plaats van ze tijdens runtime te genereren. Deze modus wordt geactiveerd wanneer de XmlSerializer geschikte serialisatieassembly kan vinden. De XmlSerializer controles of de serialisatieassembly al dan niet is ondertekend door dezelfde sleutel die is gebruikt om de assembly te ondertekenen die de typen bevat die worden geserialiseerd. Dit biedt bescherming tegen schadelijke assembly's die worden vermomd als serialisatieassembly's. Als de assembly met uw serialiseerbare typen echter niet is ondertekend, kan deze XmlSerializer controle niet worden uitgevoerd en wordt een assembly met de juiste naam gebruikt. Hierdoor is het uitvoeren van schadelijke code mogelijk. Onderteken altijd de assembly's die uw serialiseerbare typen bevatten of beheer de toegang tot de map van uw toepassing en de globale assemblycache om te voorkomen dat schadelijke assembly's worden gebruikt.
De XmlSerializer kan worden onderworpen aan een Denial of Service-aanval. Het XmlSerializer quotum heeft geen MaxItemsInObjectGraph
quotum (zoals beschikbaar is op de DataContractSerializer). Hierdoor wordt een willekeurige hoeveelheid objecten gedeserialiseerd, alleen beperkt door de berichtgrootte.
Gedeeltelijke vertrouwensbedreigingen
Let op de volgende problemen met betrekking tot bedreigingen die betrekking hebben op code die wordt uitgevoerd met gedeeltelijke vertrouwensrelatie. Deze bedreigingen omvatten schadelijke gedeeltelijk vertrouwde code en kwaadwillende gedeeltelijk vertrouwde code in combinatie met andere aanvalsscenario's (bijvoorbeeld gedeeltelijk vertrouwde code waarmee een specifieke tekenreeks wordt samengesteld en vervolgens deserialiseren).
Wanneer u serialisatieonderdelen gebruikt, moet u nooit machtigingen vóór dit gebruik bevestigen, zelfs als het volledige serialisatiescenario binnen het bereik van uw assert valt en u niet te maken hebt met niet-vertrouwde gegevens of objecten. Dit gebruik kan leiden tot beveiligingsproblemen.
In gevallen waarin gedeeltelijk vertrouwde code controle heeft over het serialisatieproces, hetzij via uitbreidbaarheidspunten (surrogaten), typen die worden geserialiseerd of via een andere methode, kan de gedeeltelijk vertrouwde code ertoe leiden dat de serialisatiefunctie een grote hoeveelheid gegevens naar de geserialiseerde stroom uitvoert, wat Denial of Service (DoS) kan veroorzaken voor de ontvanger van deze stroom. Als u gegevens serialiseert die zijn bedoeld voor een doel dat gevoelig is voor DoS-bedreigingen, serialiseert u niet gedeeltelijk vertrouwde typen of laat u op een andere manier gedeeltelijk vertrouwde codebeheer serialiseren.
Als u gedeeltelijk vertrouwde codetoegang tot uw DataContractSerializer exemplaar toestaat of anderszins de surrogaten van het gegevenscontract beheert, kan het veel controle uitoefenen over het serialisatie-/deserialisatieproces. Het kan bijvoorbeeld willekeurige typen injecteren, leiden tot openbaarmaking van informatie, manipulatie met de resulterende objectgrafiek of geserialiseerde gegevens, of de resulterende geserialiseerde stroom overlopen. Een equivalente NetDataContractSerializer bedreiging wordt beschreven in de sectie 'Using the NetDataContractSerializer Securely'.
Als het DataContractAttribute kenmerk wordt toegepast op een type (of het type dat is gemarkeerd als SerializableAttribute maar niet ISerializable), kan de deserializer een exemplaar van een dergelijk type maken, zelfs als alle constructors niet openbaar of beveiligd zijn door eisen.
Vertrouw nooit het resultaat van deserialisatie, tenzij de gegevens die moeten worden gedeserialiseerd worden vertrouwd en u zeker weet dat alle bekende typen typen zijn die u vertrouwt. Houd er rekening mee dat bekende typen niet worden geladen vanuit het configuratiebestand van de toepassing (maar worden geladen vanuit het configuratiebestand van de computer) wanneer ze worden uitgevoerd in gedeeltelijke vertrouwensrelatie.
Als u een DataContractSerializer exemplaar doorgeeft met een surrogaat dat is toegevoegd aan gedeeltelijk vertrouwde code, kan de code alle gewijzigde instellingen voor die surrogaat wijzigen.
Als voor een gedeserialiseerd object de XML-lezer (of de gegevens daarin) afkomstig is van gedeeltelijk vertrouwde code, behandelt u het resulterende gedeserialiseerde object als niet-vertrouwde gegevens.
Het feit dat het ExtensionDataObject type geen openbare leden heeft, betekent niet dat gegevens in het type veilig zijn. Als u bijvoorbeeld deserialiseert van een bevoegde gegevensbron in een object waarin sommige gegevens zich bevinden, kunt u dat object vervolgens overdragen aan gedeeltelijk vertrouwde code, kan de gedeeltelijk vertrouwde code de gegevens in het
ExtensionDataObject
object lezen door het object te serialiseren. Overweeg deze instelling in tetrue
stellen IgnoreExtensionDataObject bij het deserialiseren van een bevoegde gegevensbron in een object dat later wordt doorgegeven aan gedeeltelijk vertrouwde code.DataContractSerializer en DataContractJsonSerializer ondersteunt de serialisatie van persoonlijke, beveiligde, interne en openbare leden in volledig vertrouwen. In gedeeltelijke vertrouwensrelatie kunnen echter alleen openbare leden worden geserialiseerd. Er SecurityException wordt een gegenereerd als een toepassing probeert een niet-openbaar lid te serialiseren.
Als u wilt toestaan dat interne of beveiligde interne leden in gedeeltelijke vertrouwensrelatie worden geserialiseerd, gebruikt u het InternalsVisibleToAttribute assemblykenmerk. Met dit kenmerk kan een assembly declareren dat de interne leden zichtbaar zijn voor een andere assembly. In dit geval verklaart een assembly die de interne leden wil laten serialiseren dat de interne leden zichtbaar zijn voor System.Runtime.Serialization.dll.
Het voordeel van deze benadering is dat er geen pad voor het genereren van code met verhoogde bevoegdheden is vereist.
Tegelijkertijd zijn er twee belangrijke nadelen.
Het eerste nadeel is dat de opt-in-eigenschap van het InternalsVisibleToAttribute kenmerk assemblybreed is. Dat wil gezegd, u kunt niet opgeven dat alleen een bepaalde klasse de interne leden kan laten serialiseren. Natuurlijk kunt u er nog steeds voor kiezen om een specifiek intern lid niet te serialiseren door gewoon geen kenmerk aan dat lid toe te voegen DataMemberAttribute . Een ontwikkelaar kan er ook voor kiezen om een lid intern te maken in plaats van privé of beveiligd, met lichte zichtbaarheidsproblemen.
Het tweede nadeel is dat het nog steeds geen privé- of beschermde leden ondersteunt.
Bekijk het volgende programma om het gebruik van het InternalsVisibleToAttribute kenmerk in gedeeltelijke vertrouwensrelatie te illustreren:
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"; } }
In het bovenstaande
PermissionsHelper.InternetZone
voorbeeld komt dit overeen met de PermissionSet voor gedeeltelijke vertrouwensrelatie. Zonder het InternalsVisibleToAttribute kenmerk mislukt de toepassing, waardoor wordt SecurityException aangegeven dat niet-openbare leden niet in gedeeltelijke vertrouwensrelatie kunnen worden geserialiseerd.Als we echter de volgende regel toevoegen aan het bronbestand, wordt het programma uitgevoerd.
[assembly:System.Runtime.CompilerServices.InternalsVisibleTo("System.Runtime.Serialization, PublicKey = 00000000000000000400000000000000")]
Andere problemen met statusbeheer
Enkele andere problemen met betrekking tot objectstatusbeheer zijn het vermelden waard:
Wanneer u het stream-gebaseerde programmeermodel gebruikt met een streamingtransport, treedt de verwerking van het bericht op wanneer het bericht binnenkomt. De afzender van het bericht kan de verzendbewerking in het midden van de stream afbreken, waardoor uw code onvoorspelbaar blijft als er meer inhoud werd verwacht. In het algemeen vertrouwt u niet op de stroom die is voltooid en voert u geen werk uit in een stroombewerking die niet kan worden teruggedraaid voor het geval de stream wordt afgebroken. Dit geldt ook voor de situatie waarin een bericht ongeldig kan zijn na de streamingtekst (er ontbreekt bijvoorbeeld mogelijk een eindcode voor de SOAP-envelop of een tweede berichttekst).
Het gebruik van de
IExtensibleDataObject
functie kan ertoe leiden dat gevoelige gegevens worden verzonden. Als u gegevens van een niet-vertrouwde bron accepteert in gegevenscontracten metIExtensibleObjectData
en deze later opnieuw verzendt op een beveiligd kanaal waar berichten zijn ondertekend, kunt u gegevens waarover u niets weet toevoegen. Bovendien kan de algehele status die u verzendt ongeldig zijn als u rekening houdt met zowel de bekende als onbekende gegevens. Vermijd deze situatie door de eigenschap extensiegegevens selectief in tenull
stellen of door deIExtensibleObjectData
functie selectief uit te schakelen.
Schema importeren
Normaal gesproken gebeurt het proces van het importeren van schema voor het genereren van typen alleen tijdens het ontwerp, bijvoorbeeld wanneer u het Hulpprogramma voor metagegevens van ServiceModel (Svcutil.exe) op een webservice gebruikt om een clientklasse te genereren. In meer geavanceerde scenario's kunt u echter schema's tijdens runtime verwerken. Houd er rekening mee dat u hiermee risico's van denial-of-service kunt maken. Het kan lang duren voordat een bepaald schema is geïmporteerd. Gebruik nooit het XmlSerializer importonderdeel schema in dergelijke scenario's als schema's mogelijk afkomstig zijn van een niet-vertrouwde bron.
Bedreigingen die specifiek zijn voor ASP.NET AJAX-integratie
Wanneer de gebruiker een eindpunt implementeert WebScriptEnablingBehavior of WebHttpBehavior, maakt WCF een eindpunt beschikbaar dat zowel XML- als JSON-berichten kan accepteren. Er is echter slechts één set lezersquota die zowel door de XML-lezer als de JSON-lezer worden gebruikt. Sommige quota-instellingen zijn mogelijk geschikt voor één lezer, maar te groot voor de andere.
Bij het implementeren WebScriptEnablingBehavior
heeft de gebruiker de mogelijkheid om een JavaScript-proxy beschikbaar te maken op het eindpunt. De volgende beveiligingsproblemen moeten worden overwogen:
Informatie over de service (bewerkingsnamen, parameternamen, enzovoort) kan worden verkregen door de JavaScript-proxy te onderzoeken.
Wanneer u het JavaScript-eindpunt gebruikt, kunnen gevoelige en persoonlijke gegevens worden bewaard in de cache van de webbrowser van de client.
Een opmerking over onderdelen
WCF is een flexibel en aanpasbaar systeem. De meeste inhoud van dit onderwerp is gericht op de meest voorkomende WCF-gebruiksscenario's. Het is echter mogelijk om onderdelen op te stellen die WCF op veel verschillende manieren biedt. Het is belangrijk om inzicht te krijgen in de gevolgen voor de beveiliging van het gebruik van elk onderdeel. Met name:
Wanneer u XML-lezers moet gebruiken, gebruikt u de lezers die de XmlDictionaryReader klasse biedt in plaats van andere lezers. Veilige lezers worden gemaakt met behulp van CreateTextReader, CreateBinaryReaderof CreateMtomReader methoden. Gebruik de Create methode niet. Configureer de lezers altijd met veilige quota. De serialisatie-engines in WCF zijn alleen beveiligd wanneer ze worden gebruikt met beveiligde XML-lezers van WCF.
Wanneer u de DataContractSerializer eigenschap gebruikt om mogelijk niet-vertrouwde gegevens te deserialiseren, moet u altijd de MaxItemsInObjectGraph eigenschap instellen.
Wanneer u een bericht maakt, stelt u de
maxSizeOfHeaders
parameter in alsMaxReceivedMessageSize
deze niet voldoende beveiliging biedt.Bij het maken van een encoder configureert u altijd de relevante quota, zoals
MaxSessionSize
enMaxBufferSize
.Wanneer u een XPath-berichtfilter gebruikt, stelt u de NodeQuota waarde in om de hoeveelheid XML-knooppunten te beperken die door het filter worden bezocht. Gebruik geen XPath-expressies die lang kunnen duren om te berekenen zonder veel knooppunten te bezoeken.
Wanneer u een onderdeel gebruikt dat een quotum accepteert, begrijpt u de gevolgen van de beveiliging en stelt u dit in op een veilige waarde.