Klasse System.Security.Cryptography.Xml.SignedXml
In dit artikel vindt u aanvullende opmerkingen in de referentiedocumentatie voor deze API.
De SignedXml klasse is de .NET-implementatie van het World Wide Web Consortium (W3C) XML Signature Syntax and Processing Specification, ook wel bekend als XMLDSIG (XML Digital Signature). XMLDSIG is een op standaarden gebaseerde, interoperabele manier om alle of een deel van een XML-document of andere gegevens te ondertekenen en te verifiëren die kunnen worden adresseerbaar vanuit een URI (Uniform Resource Identifier).
Gebruik de SignedXml klasse wanneer u ondertekende XML-gegevens wilt delen tussen toepassingen of organisaties op een standaard manier. Alle gegevens die met deze klasse zijn ondertekend, kunnen worden geverifieerd door elke conforme implementatie van de W3C-specificatie voor XMLDSIG.
Met SignedXml de klasse kunt u de volgende drie soorten DIGITALE XML-handtekeningen maken:
Handtekeningtype | Beschrijving |
---|---|
Handtekening met envelop | De handtekening bevindt zich in het XML-element dat wordt ondertekend. |
Enveloppende handtekening | De ondertekende XML bevindt zich in het <Signature> element. |
Interne losgekoppelde handtekening | De handtekening en de ondertekende XML bevinden zich in hetzelfde document, maar geen van beide elementen bevat het andere element. |
Er is ook een vierde soort handtekening, een externe, losgekoppelde handtekening, namelijk wanneer de gegevens en handtekening zich in afzonderlijke XML-documenten bevinden. Externe losgekoppelde handtekeningen worden niet ondersteund door de SignedXml klasse.
Structuur van een XML-handtekening
XMLDSIG maakt een <Signature>
element dat een digitale handtekening bevat van een XML-document of andere gegevens die kunnen worden adresseerbaar vanuit een URI. Het <Signature>
element kan eventueel informatie bevatten over waar u een sleutel kunt vinden die de handtekening verifieert en welk cryptografisch algoritme is gebruikt voor ondertekening. De basisstructuur is als volgt:
<Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>Base64EncodedValue==</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>AnotherBase64EncodedValue===</SignatureValue>
</Signature>
De belangrijkste onderdelen van deze structuur zijn:
Het
<CanonicalizationMethod>
elementHiermee geeft u de regels voor het herschrijven van het
Signature
element van XML/tekst in bytes voor handtekeningvalidatie. De standaardwaarde in .NET is http://www.w3.org/TR/2001/REC-xml-c14n-20010315, waarmee een betrouwbaar algoritme wordt geïdentificeerd. Dit element wordt vertegenwoordigd door de SignedInfo.CanonicalizationMethod eigenschap.Het
<SignatureMethod>
elementHiermee geeft u het algoritme op dat wordt gebruikt voor het genereren en valideren van handtekeningen, die is toegepast op het
<Signature>
element om de waarde in<SignatureValue>
te produceren. In het vorige voorbeeld identificeert de waarde http://www.w3.org/2000/09/xmldsig#rsa-sha1 een RSA PKCS1 SHA-1-handtekening. Vanwege conflictproblemen met SHA-1 raadt Microsoft een beveiligingsmodel aan op basis van SHA-256 of beter. Dit element wordt vertegenwoordigd door de SignatureMethod eigenschap.Het
<SignatureValue>
elementHiermee geeft u de cryptografische handtekening voor het
<Signature>
element. Als deze handtekening niet controleert, is er met een deel van het<Signature>
blok geknoeid en wordt het document als ongeldig beschouwd. Zolang de<CanonicalizationMethod>
waarde betrouwbaar is, is deze waarde zeer bestand tegen manipulatie. Dit element wordt vertegenwoordigd door de SignatureValue eigenschap.Het
URI
kenmerk van het<Reference>
elementHiermee geeft u een gegevensobject op met behulp van een URI-verwijzing. Dit kenmerk wordt vertegenwoordigd door de Reference.Uri eigenschap.
Als u het
URI
kenmerk niet opgeeft, betekent dit dat de Reference.Urinull
ontvangende toepassing naar verwachting de identiteit van het object kent. In de meeste gevallen leidt eennull
URI ertoe dat er een uitzondering wordt gegenereerd. Gebruik geennull
URI, tenzij uw toepassing werkt met een protocol dat dit vereist.Als u het
URI
kenmerk instelt op een lege tekenreeks, wordt aangegeven dat het hoofdelement van het document wordt ondertekend, een vorm van een envelophandtekening.Als de waarde van
URI
het kenmerk begint met #, moet de waarde worden omgezet in een element in het huidige document. Dit formulier kan worden gebruikt met een van de ondersteunde handtekeningtypen (envelophandtekening, envelophandtekening of interne losgekoppelde handtekening).Iets anders wordt beschouwd als een handtekening voor externe resources die is losgekoppeld en wordt niet ondersteund door de SignedXml klasse.
Het
<Transforms>
elementBevat een geordende lijst
<Transform>
met elementen die beschrijven hoe de ondertekenaar het gegevensobject heeft verkregen dat is verwerkt. Een transformatiealgoritme is vergelijkbaar met de canonicalisatiemethode, maar in plaats van het<Signature>
element te herschrijven, herschrijft het de inhoud die wordt geïdentificeerd door hetURI
kenmerk van het<Reference>
element. Het<Transforms>
element wordt vertegenwoordigd door de TransformChain klasse.Elk transformatie-algoritme wordt gedefinieerd als het nemen van XML (een XPath-knooppuntset) of bytes als invoer. Als de indeling van de huidige gegevens verschilt van de invoervereisten voor transformatie, worden conversieregels toegepast.
Elk transformatie-algoritme wordt gedefinieerd als het produceren van XML of bytes als uitvoer.
Als de uitvoer van het laatste transformatie-algoritme niet is gedefinieerd in bytes (of er zijn geen transformaties opgegeven), wordt de canonicalisatiemethode gebruikt als een impliciete transformatie (zelfs als er een ander algoritme is opgegeven in het
<CanonicalizationMethod>
element).Een waarde van http://www.w3.org/2000/09/xmldsig#enveloped-signature het transformatiealgoritmen codeert een regel die wordt geïnterpreteerd als het
<Signature>
element uit het document verwijderen. Anders wordt het document door een verificator van een handtekening met enveloppen verwerkt, inclusief de handtekening, maar de ondertekenaar zou het document hebben verwerkt voordat de handtekening werd toegepast, wat leidt tot verschillende antwoorden.
Het
<DigestMethod>
elementIdentificeert de digest-methode (cryptografische hash) die moet worden toegepast op de getransformeerde inhoud die wordt geïdentificeerd door het
URI
kenmerk van het<Reference>
element. Dit wordt vertegenwoordigd door de Reference.DigestMethod eigenschap.
Een canonicalisatiemethode kiezen
Tenzij u werkt met een specificatie waarvoor het gebruik van een andere waarde is vereist, raden we u aan de standaard .NET-canonicalisatiemethode te gebruiken. Dit is het XML-C14N 1.0-algoritme, waarvan de waarde is http://www.w3.org/TR/2001/REC-xml-c14n-20010315. Het XML-C14N 1.0-algoritme moet worden ondersteund door alle implementaties van XMLDSIG, met name omdat het een impliciete uiteindelijke transformatie is die moet worden toegepast.
Er zijn versies van canonicalisatiealgoritmen die ondersteuning bieden voor het behouden van opmerkingen. Canonicalisatiemethoden die opmerkingen behouden, worden niet aanbevolen omdat ze het principe 'teken wat wordt gezien' schenden. Dat wil zeggen dat de opmerkingen in een <Signature>
element de verwerkingslogica niet wijzigen voor de manier waarop de handtekening wordt uitgevoerd, alleen wat de handtekeningwaarde is. In combinatie met een zwak handtekening-algoritme, waardoor de opmerkingen kunnen worden opgenomen, geeft een aanvaller onnodige vrijheid om een hash-botsing te forceren, waardoor een geknoeid document legitiem lijkt. In .NET Framework worden standaard alleen ingebouwde canonicalizers ondersteund. Zie de SafeCanonicalizationMethods eigenschap als u aanvullende of aangepaste canonicalizers wilt ondersteunen. Als het document gebruikmaakt van een canonicalisatiemethode die niet in de verzameling staat die wordt vertegenwoordigd door de SafeCanonicalizationMethods eigenschap, wordt de CheckSignature methode geretourneerd false
.
Notitie
Een uiterst defensieve toepassing kan alle waarden verwijderen die niet verwacht worden gebruikt door ondertekenaars uit de SafeCanonicalizationMethods verzameling.
Zijn de referentiewaarden veilig tegen manipulatie?
Ja, de <Reference>
waarden zijn veilig tegen manipulatie. .NET verifieert de <SignatureValue>
berekening voordat een van de <Reference>
waarden en de bijbehorende transformaties worden verwerkt en zal vroeg afbreken om mogelijk schadelijke verwerkingsinstructies te voorkomen.
Kies de elementen die u wilt ondertekenen
U wordt aangeraden de waarde van '' te gebruiken voor het URI
kenmerk (of stel de Uri eigenschap in op een lege tekenreeks), indien mogelijk. Dit betekent dat het hele document wordt overwogen voor de samenvattingsberekening, wat betekent dat het hele document wordt beschermd tegen manipulatie.
Het is heel gebruikelijk om waarden te zien URI
in de vorm van ankers, zoals #foo, die verwijst naar een element waarvan het id-kenmerk 'foo' is. Helaas is het eenvoudig om hiermee te worden geknoeid, omdat dit alleen de inhoud van het doelelement bevat, niet de context. Dit onderscheid wordt ook wel XML Signature Wrapping (XSW) genoemd.
Als uw toepassing van mening is dat opmerkingen semantisch zijn (wat niet gebruikelijk is bij het omgaan met XML), moet u '#xpointer(/)' gebruiken in plaats van '' en '#xpointer(id('foo'))) in plaats van '#foo'. De #xpointer versies worden geïnterpreteerd als opmerkingen, terwijl de korte naamformulieren opmerkingen uitsluiten.
Als u documenten wilt accepteren die slechts gedeeltelijk zijn beveiligd en u ervoor wilt zorgen dat u dezelfde inhoud leest die door de handtekening is beveiligd, gebruikt u de GetIdElement methode.
Beveiligingsoverwegingen over het KeyInfo-element
De gegevens in het optionele <KeyInfo>
element (dat wil gezegd de KeyInfo eigenschap) die een sleutel bevat om de handtekening te valideren, mogen niet worden vertrouwd.
Met name wanneer de KeyInfo waarde een openbare RSA-, DSA- of ECDSA-sleutel vertegenwoordigt, is het document mogelijk gemanipuleerd, ondanks de CheckSignature methode die meldt dat de handtekening geldig is. Dit kan gebeuren omdat de entiteit die de manipulatie uitvoert alleen een nieuwe sleutel moet genereren en het geknoeid document opnieuw moet ondertekenen met die nieuwe sleutel. Dus, tenzij uw toepassing controleert of de openbare sleutel een verwachte waarde is, moet het document worden behandeld alsof er met het document is geknoeid. Hiervoor moet uw toepassing de openbare sleutel die in het document is ingesloten, onderzoeken en controleren op basis van een lijst met bekende waarden voor de documentcontext. Als het document bijvoorbeeld kan worden begrepen door een bekende gebruiker, controleert u de sleutel op basis van een lijst met bekende sleutels die door die gebruiker worden gebruikt.
U kunt de sleutel ook controleren nadat het document is verwerkt met behulp van de CheckSignatureReturningKey methode, in plaats van de CheckSignature methode. Maar voor de optimale beveiliging moet u de sleutel vooraf verifiëren.
U kunt ook overwegen om de geregistreerde openbare sleutels van de gebruiker uit te proberen in plaats van te lezen wat er in het <KeyInfo>
element staat.
Beveiligingsoverwegingen over het element X509Data
Het optionele element is een onderliggend <X509Data>
<KeyInfo>
element en bevat een of meer X509-certificaten of -id's voor X509-certificaten. De gegevens in het <X509Data>
element mogen ook niet inherent worden vertrouwd.
Wanneer u een document verifieert met het ingesloten <X509Data>
element, controleert .NET alleen of de gegevens worden omgezet in een X509-certificaat waarvan de openbare sleutel kan worden gebruikt om de documenthandtekening te valideren. In tegenstelling tot het aanroepen van de CheckSignature methode waarvoor de verifySignatureOnly
parameter is ingesteld false
, wordt er geen intrekkingscontrole uitgevoerd, wordt er geen ketenvertrouwen gecontroleerd en wordt er geen vervaldatum geverifieerd. Zelfs als uw toepassing het certificaat zelf extraheert en doorgeeft aan de CheckSignature methode waarop de verifySignatureOnly
parameter is ingesteld false
, is dat nog steeds niet voldoende validatie om te voorkomen dat documenten worden geknoeid. Het certificaat moet nog steeds worden geverifieerd als geschikt voor het document dat wordt ondertekend.
Het gebruik van een ingesloten handtekeningcertificaat kan nuttige strategieën voor sleutelrotatie bieden, in de <X509Data>
sectie of in de documentinhoud. Wanneer u deze methode gebruikt, moet een toepassing het certificaat handmatig extraheren en validatie uitvoeren die vergelijkbaar is met:
Het certificaat is rechtstreeks of via een keten uitgegeven door een certificeringsinstantie (CA) waarvan het openbare certificaat is ingesloten in de toepassing.
Het gebruik van de door het besturingssysteem verstrekte vertrouwenslijst zonder extra controles, zoals een bekende onderwerpnaam, is niet voldoende om manipulatie in SignedXmlte voorkomen.
Het certificaat is geverifieerd dat het niet is verlopen op het moment van documentondertekening (of nu voor bijna realtime documentverwerking).
Controleer of het certificaat niet is ingetrokken voor certificaten die zijn uitgegeven door een CA die intrekking ondersteunt.
Het certificaatonderwerp wordt geverifieerd als geschikt voor het huidige document.
Het transformatie-algoritme kiezen
Als u werkt met een specificatie die specifieke waarden (zoals XrML) heeft gedicteerd, moet u de specificatie volgen. Als u een handtekening met enveloppen hebt (bijvoorbeeld bij het ondertekenen van het hele document), moet u deze gebruiken http://www.w3.org/2000/09/xmldsig#enveloped-signature (vertegenwoordigd door de XmlDsigEnvelopedSignatureTransform klas). U kunt ook de impliciete XML-C14N-transformatie opgeven, maar dit is niet nodig. Voor een envelop- of losgekoppelde handtekening zijn er geen transformaties vereist. De impliciete XML-C14N-transformatie zorgt voor alles.
Met de beveiliging die is bijgewerkt door het Microsoft-beveiligingsbulletin MS16-035, heeft .NET beperkt welke transformaties standaard kunnen worden gebruikt bij documentverificatie, met niet-vertrouwde transformaties die ervoor zorgen dat CheckSignature altijd wordt geretourneerd false
. Met name transformaties waarvoor aanvullende invoer is vereist (opgegeven als onderliggende elementen in de XML) zijn niet langer toegestaan vanwege hun gevoeligheid voor misbruik door kwaadwillende gebruikers. De W3C adviseert om de XPath- en XSLT-transformaties te vermijden. Dit zijn de twee belangrijkste transformaties die worden beïnvloed door deze beperkingen.
Het probleem met externe verwijzingen
Als een toepassing niet controleert of externe verwijzingen geschikt lijken voor de huidige context, kunnen ze worden misbruikt op manieren die veel beveiligingsproblemen bieden (waaronder Denial of Service, Distributed Reflection Denial of Service, Openbaarmaking van informatie, Handtekening omzeilen en Uitvoering van externe code). Zelfs als een toepassing de externe referentie-URI zou valideren, zou er een probleem blijven dat de resource tweemaal wordt geladen: eenmaal wanneer uw toepassing deze leest en eenmaal wanneer SignedXml deze wordt gelezen. Omdat er geen garantie is dat de stappen voor het lezen en controleren van documenten van de toepassing dezelfde inhoud hebben, biedt de handtekening geen betrouwbaarheid.
Gezien de risico's van externe verwijzingen wordt SignedXml een uitzondering gegenereerd wanneer een externe verwijzing wordt aangetroffen. Zie KB-artikel 3148821 voor meer informatie over dit probleem.