System.Security.Cryptography.Xml.SignedXml, klasa

Ten artykuł zawiera dodatkowe uwagi dotyczące dokumentacji referencyjnej dla tego interfejsu API.

Klasa to implementacja SignedXml platformy .NET składni i przetwarzania xml konsorcjum World Wide Web Consortium (W3C), znana również jako XMLDSIG (podpis cyfrowy XML). XMLDSIG to oparty na standardach, współdziałanie sposób podpisywania i weryfikowania wszystkich lub części dokumentu XML lub innych danych, które można adresować z identyfikatora URI (Uniform Resource Identifier).

SignedXml Użyj klasy zawsze, gdy musisz udostępniać podpisane dane XML między aplikacjami lub organizacjami w standardowy sposób. Wszystkie dane podpisane przy użyciu tej klasy można zweryfikować za pomocą dowolnej zgodnej implementacji specyfikacji W3C dla XMLDSIG.

Klasa SignedXml umożliwia utworzenie następujących trzech rodzajów podpisów cyfrowych XML:

Typ podpisu opis
Podpis kopertowy Podpis jest zawarty w podpisie elementu XML.
Podpis ukośny Podpisany kod XML znajduje się w elemecie <Signature> .
Wewnętrzny odłączony podpis Podpis i podpisany kod XML znajdują się w tym samym dokumencie, ale żaden element nie zawiera drugiego.

Istnieje również czwarty rodzaj podpisu nazywany zewnętrznym odłączonym podpisem, który jest wtedy, gdy dane i podpis znajdują się w oddzielnych dokumentach XML. Sygnatury odłączone zewnętrznie nie są obsługiwane przez klasę SignedXml .

Struktura podpisu XML

XMLDSIG tworzy <Signature> element, który zawiera podpis cyfrowy dokumentu XML lub innych danych, które są adresowalne z identyfikatora URI. Element <Signature> może opcjonalnie zawierać informacje o tym, gdzie znaleźć klucz, który zweryfikuje podpis i który algorytm kryptograficzny został użyty do podpisywania. Podstawowa struktura jest następująca:

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

Główne części tej struktury to:

  • Element <CanonicalizationMethod>

    Określa reguły ponownego zapisywania Signature elementu z xml/tekstu do bajtów na potrzeby walidacji podpisu. Wartość domyślna na platformie .NET to http://www.w3.org/TR/2001/REC-xml-c14n-20010315, która identyfikuje zaufany algorytm. Ten element jest reprezentowany SignedInfo.CanonicalizationMethod przez właściwość .

  • Element <SignatureMethod>

    Określa algorytm używany do generowania i walidacji podpisów, który został zastosowany do <Signature> elementu w celu wygenerowania wartości w <SignatureValue>pliku . W poprzednim przykładzie wartość http://www.w3.org/2000/09/xmldsig#rsa-sha1 identyfikuje podpis SHA-1 RSA PKCS1. Ze względu na problemy z kolizją z algorytmem SHA-1 firma Microsoft zaleca model zabezpieczeń oparty na algorytmie SHA-256 lub lepszym. Ten element jest reprezentowany SignatureMethod przez właściwość .

  • Element <SignatureValue>

    Określa podpis kryptograficzny elementu <Signature> . Jeśli ten podpis nie zostanie zweryfikowany, część <Signature> bloku została naruszona, a dokument jest uznawany za nieprawidłowy. Tak długo, jak <CanonicalizationMethod> wartość jest godna zaufania, ta wartość jest wysoce odporna na manipulowanie. Ten element jest reprezentowany SignatureValue przez właściwość .

  • Atrybut URI<Reference> elementu

    Określa obiekt danych przy użyciu odwołania do identyfikatora URI. Ten atrybut jest reprezentowany Reference.Uri przez właściwość .

    • Nie określa atrybutu URI , czyli ustawiania Reference.Uri właściwości na null, oznacza, że aplikacja odbierającej ma znać tożsamość obiektu. W większości przypadków null identyfikator URI spowoduje zgłoszenie wyjątku. Nie używaj identyfikatora null URI, chyba że aplikacja współdziała z protokołem, który go wymaga.

    • Ustawienie atrybutu URI na pusty ciąg wskazuje, że element główny dokumentu jest podpisany, forma podpisu kopertowego.

    • Jeśli wartość atrybutu URI zaczyna się od #, wartość musi zostać rozpoznana jako element w bieżącym dokumencie. Ten formularz może być używany z dowolnym z obsługiwanych typów podpisów (sygnatura kopertowa, otaczanie podpisu lub wewnętrzny odłączony podpis).

    • Wszystkie inne elementy są uznawane za sygnaturę odłączonego zasobu zewnętrznego i nie są obsługiwane przez klasę SignedXml .

  • Element <Transforms>

    Zawiera uporządkowaną listę <Transform> elementów opisujących sposób uzyskiwania obiektu danych, który został szyfrowany przez znak. Algorytm przekształcania jest podobny do metody canonicalization, ale zamiast ponownie zapisywać <Signature> element, ponownie zapisuje zawartość zidentyfikowaną przez URI atrybut <Reference> elementu. Element <Transforms> jest reprezentowany przez klasę TransformChain .

    • Każdy algorytm przekształcania jest definiowany jako przyjmujący kod XML (zestaw węzłów XPath) lub bajty jako dane wejściowe. Jeśli format bieżących danych różni się od wymagań dotyczących przekształcania danych wejściowych, stosowane są reguły konwersji.

    • Każdy algorytm przekształcania jest definiowany jako tworzący kod XML lub bajty jako dane wyjściowe.

    • Jeśli dane wyjściowe ostatniego algorytmu przekształcania nie są zdefiniowane w bajtach (lub nie określono żadnych przekształceń), metoda kanoniczna jest używana jako niejawna transformacja (nawet jeśli w elemecie <CanonicalizationMethod> określono inny algorytm).

    • Wartość http://www.w3.org/2000/09/xmldsig#enveloped-signature dla algorytmu przekształcania koduje regułę, która jest interpretowana jako usuwanie <Signature> elementu z dokumentu. W przeciwnym razie weryfikator sygnatury koperty będzie szyfrował dokument, w tym podpis, ale podpis przetrawiłby dokument przed zastosowaniem podpisu, co prowadzi do różnych odpowiedzi.

  • Element <DigestMethod>

    Identyfikuje metodę skrótu szyfrowanego (skrótu kryptograficznego), która ma być stosowana w przekształconej zawartości zidentyfikowanej przez URI atrybut <Reference> elementu. Jest to reprezentowane Reference.DigestMethod przez właściwość .

Wybieranie metody kanonicznej

Jeśli nie będziemy współpracować ze specyfikacją, która wymaga użycia innej wartości, zalecamy użycie domyślnej metody kanonizacji platformy .NET, czyli algorytmu XML-C14N 1.0, którego wartość to http://www.w3.org/TR/2001/REC-xml-c14n-20010315. Algorytm XML-C14N 1.0 musi być obsługiwany przez wszystkie implementacje XMLDSIG, szczególnie ponieważ jest to niejawna ostateczna transformacja do zastosowania.

Istnieją wersje algorytmów kanonizacji, które obsługują zachowywanie komentarzy. Metody kanonizacji zachowujące komentarze nie są zalecane, ponieważ naruszają zasadę "znak, co jest postrzegane". Oznacza to, że komentarze w elemecie <Signature> nie zmienią logiki przetwarzania dla sposobu wykonywania podpisu, tylko tego, jaka jest wartość podpisu. W połączeniu ze słabym algorytmem podpisu, zezwolenie na dołączenie komentarzy daje atakującemu niepotrzebną swobodę wymusić kolizję skrótu, co sprawia, że naruszony dokument wydaje się uzasadniony. W programie .NET Framework domyślnie obsługiwane są tylko wbudowane kanonizatory. Aby obsługiwać dodatkowe lub niestandardowe moduły kanoniczne, zobacz SafeCanonicalizationMethods właściwość . Jeśli dokument używa metody kanonicznej, która nie znajduje się w kolekcji reprezentowanej przez SafeCanonicalizationMethods właściwość, CheckSignature metoda zwróci falsewartość .

Uwaga

Niezwykle defensywna aplikacja może usunąć wszelkie wartości, których nie oczekuje, aby osoby podpisające korzystały z SafeCanonicalizationMethods kolekcji.

Czy wartości referencyjne są bezpieczne przed manipulowaniem?

Tak, <Reference> wartości są bezpieczne przed manipulowaniem. Platforma .NET weryfikuje <SignatureValue> obliczenia przed przetworzeniem dowolnych <Reference> wartości i skojarzonych z nimi przekształceń, a także wcześnie przerwa, aby uniknąć potencjalnie złośliwych instrukcji przetwarzania.

Wybieranie elementów do podpisania

Zalecamy użycie wartości "" dla atrybutu URI (lub ustawienie Uri właściwości na pusty ciąg), jeśli to możliwe. Oznacza to, że cały dokument jest uznawany za obliczenia szyfrowane, co oznacza, że cały dokument jest chroniony przed manipulowaniem.

Bardzo często można zobaczyć URI wartości w postaci kotwic, takich jak #foo, odwołując się do elementu, którego atrybut ID to "foo". Niestety, łatwo jest to manipulować, ponieważ obejmuje to tylko zawartość elementu docelowego, a nie kontekst. Nadużywanie tego rozróżnienia jest nazywane zawijaniem podpisów XML (XSW).

Jeśli aplikacja uważa, że komentarze są semantyczne (co nie jest powszechne w przypadku obsługi kodu XML), należy użyć polecenia "#xpointer(/)" zamiast "" i "#xpointer(id('foo'))" zamiast "#foo". Wersje #xpointer są interpretowane jako komentarze, a formularze shortname wykluczają komentarze.

Jeśli musisz zaakceptować dokumenty, które są tylko częściowo chronione i chcesz mieć pewność, że czytasz tę samą zawartość, która jest chroniona podpisem, użyj GetIdElement metody .

Zagadnienia dotyczące zabezpieczeń elementu KeyInfo

Dane w elemecie opcjonalnym <KeyInfo> (czyli KeyInfo właściwości), który zawiera klucz do zweryfikowania podpisu, nie powinny być zaufane.

W szczególności, gdy KeyInfo wartość reprezentuje goły klucz publiczny RSA, DSA lub ECDSA, dokument mógł zostać naruszony, pomimo CheckSignature metody raportowania, że podpis jest prawidłowy. Może się tak zdarzyć, ponieważ jednostka wykonująca manipulację musi wygenerować nowy klucz i ponownie podpisać zmodyfikowany dokument przy użyciu tego nowego klucza. Dlatego, chyba że aplikacja sprawdzi, czy klucz publiczny jest oczekiwaną wartością, dokument powinien być traktowany tak, jakby został naruszony. Wymaga to, aby aplikacja zbadała klucz publiczny osadzony w dokumencie i zweryfikowała go na liście znanych wartości kontekstu dokumentu. Jeśli na przykład dokument może zostać wydany przez znanego użytkownika, sprawdź klucz pod kątem listy znanych kluczy używanych przez tego użytkownika.

Klucz można również sprawdzić po przetworzeniu dokumentu przy użyciu CheckSignatureReturningKey metody zamiast metody CheckSignature . Jednak w celu zapewnienia optymalnego bezpieczeństwa należy wcześniej zweryfikować klucz.

Alternatywnie rozważ wypróbowanie zarejestrowanych kluczy publicznych użytkownika, zamiast odczytywać zawartość elementu <KeyInfo> .

Zagadnienia dotyczące zabezpieczeń elementu X509Data

Opcjonalny <X509Data> element jest elementem podrzędnym <KeyInfo> elementu i zawiera co najmniej jeden certyfikat lub identyfikatory X509 dla certyfikatów X509. Dane w elementu <X509Data> nie powinny być również z natury zaufane.

Podczas weryfikowania dokumentu z elementem osadzonym <X509Data> platforma .NET sprawdza tylko, czy dane są rozpoznawane jako certyfikat X509, którego klucz publiczny może zostać pomyślnie użyty do zweryfikowania podpisu dokumentu. W przeciwieństwie do wywoływania CheckSignature metody z parametrem ustawionym verifySignatureOnly na falsewartość , sprawdzanie odwołania nie jest wykonywane, nie jest sprawdzane żadne zaufanie łańcucha i nie jest weryfikowane. Nawet jeśli aplikacja wyodrębnia sam certyfikat i przekazuje go do CheckSignature metody z parametrem ustawionym verifySignatureOnly na false, nadal nie jest wystarczająca walidacja, aby zapobiec manipulowaniu dokumentem. Certyfikat nadal musi zostać zweryfikowany jako odpowiedni dla podpisanego dokumentu.

Użycie osadzonego certyfikatu podpisywania może zapewnić przydatne strategie rotacji kluczy, niezależnie od tego, czy w <X509Data> sekcji, czy w zawartości dokumentu. W przypadku korzystania z tego podejścia aplikacja powinna ręcznie wyodrębnić certyfikat i przeprowadzić walidację podobną do:

  • Certyfikat został wystawiony bezpośrednio lub za pośrednictwem łańcucha przez urząd certyfikacji, którego certyfikat publiczny jest osadzony w aplikacji.

    Korzystanie z listy zaufania dostarczonej przez system operacyjny bez dodatkowych kontroli, takich jak znana nazwa podmiotu, nie jest wystarczające, aby zapobiec manipulacji w systemie SignedXml.

  • Certyfikat jest weryfikowany, aby nie wygasł w momencie podpisywania dokumentu (lub "teraz" na potrzeby przetwarzania dokumentów niemal w czasie rzeczywistym).

  • W przypadku certyfikatów długotrwałych wystawionych przez urząd certyfikacji, który obsługuje odwoływanie, sprawdź, czy certyfikat nie został odwołany.

  • Podmiot certyfikatu jest weryfikowany jako odpowiedni dla bieżącego dokumentu.

Wybieranie algorytmu przekształcania

Jeśli pracujesz ze specyfikacją, która ma określone wartości (takie jak XrML), musisz postępować zgodnie ze specyfikacją. Jeśli masz sygnaturę kopertową (np. podczas podpisywania całego dokumentu), musisz użyć http://www.w3.org/2000/09/xmldsig#enveloped-signature (reprezentowanej przez klasę XmlDsigEnvelopedSignatureTransform ). Można również określić niejawną transformację XML-C14N, ale nie jest to konieczne. W przypadku enveloping lub odłączonego podpisu nie są wymagane żadne przekształcenia. Niejawna transformacja XML-C14N zajmuje się wszystkim.

Dzięki aktualizacji zabezpieczeń wprowadzonej przez biuletyn zabezpieczeń firmy Microsoft MS16-035 platforma .NET ograniczyła, jakie przekształcenia mogą być domyślnie używane w weryfikacji dokumentów, a niezaufane przekształcenia powodują, że CheckSignature zawsze zwracany jest element false. W szczególności przekształcenia, które wymagają dodatkowych danych wejściowych (określonych jako elementy podrzędne w xml) nie są już dozwolone ze względu na ich podatność na nadużycia przez złośliwych użytkowników. W3C zaleca unikanie przekształceń XPath i XSLT, które są dwoma głównymi transformacjami, na które mają wpływ te ograniczenia.

Problem z odwołaniami zewnętrznymi

Jeśli aplikacja nie sprawdza, czy odwołania zewnętrzne wydają się odpowiednie dla bieżącego kontekstu, mogą być nadużywane w sposób zapewniający wiele luk w zabezpieczeniach (w tym odmowa usługi, rozproszona odmowa usługi Emocje ion, ujawnienie informacji, obejście podpisu i zdalne wykonywanie kodu). Nawet jeśli aplikacja miała zweryfikować identyfikator URI odwołania zewnętrznego, problem z zasobem jest ładowany dwa razy: raz, gdy aplikacja go odczytuje, a raz po SignedXml jego odczytaniu. Ponieważ nie ma gwarancji, że aplikacja odczytuje i sprawdza, czy kroki weryfikacji dokumentu mają tę samą zawartość, podpis nie zapewnia wiarygodności.

Biorąc pod uwagę ryzyko odwołań zewnętrznych, SignedXml zgłasza wyjątek w przypadku napotkania odwołania zewnętrznego. Aby uzyskać więcej informacji na temat tego problemu, zobacz artykuł kb 3148821.