Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Observação
Este artigo fornece observações complementares à documentação de referência para esta API.
A SignedXml classe é a implementação .NET da World Wide Web Consortium (W3C) XML Signature Syntax and Processing Specification, também conhecida como XMLDSIG (XML Digital Signature). XMLDSIG é uma maneira interoperável baseada em padrões para assinar e verificar todo ou parte de um documento XML ou outros dados endereçáveis a partir de um URI (Uniform Resource Identifier).
Use a SignedXml classe sempre que precisar compartilhar dados XML assinados entre aplicativos ou organizações de forma padrão. Todos os dados assinados usando esta classe podem ser verificados por qualquer implementação em conformidade da especificação W3C para XMLDSIG.
A SignedXml classe permite que você crie os seguintes três tipos de assinaturas digitais XML:
| Tipo de assinatura | Descrição |
|---|---|
| Assinatura envelopada | A assinatura está contida no elemento XML que está sendo assinado. |
| Assinatura envolvente | O XML assinado está contido no <Signature> elemento . |
| Assinatura interna desanexada | A assinatura e o XML assinado estão no mesmo documento, mas nenhum elemento contém o outro. |
Há também um quarto tipo de assinatura chamada assinatura externa separada, que é quando os dados e a assinatura estão em documentos XML separados. As assinaturas externas desanexadas não são suportadas pela classe SignedXml.
Estrutura de uma assinatura XML
XMLDSIG cria um <Signature> elemento , que contém uma assinatura digital de um documento XML ou outros dados que são endereçáveis a partir de um URI. Opcionalmente, o <Signature> elemento pode conter informações sobre onde encontrar uma chave que verificará a assinatura e qual algoritmo criptográfico foi usado para assinatura. A estrutura básica é a seguinte:
<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>
As principais partes desta estrutura são:
O
<CanonicalizationMethod>elementoEspecifica as regras para reescrever o
Signatureelemento de XML/texto em bytes para validação de assinatura. O valor padrão no .NET é http://www.w3.org/TR/2001/REC-xml-c14n-20010315, que identifica um algoritmo confiável. Este elemento é representado pela SignedInfo.CanonicalizationMethod propriedade.O
<SignatureMethod>elementoEspecifica o algoritmo usado para geração e validação de assinaturas, que foi aplicado ao
<Signature>elemento para produzir o valor em<SignatureValue>. No exemplo anterior, o valor http://www.w3.org/2000/09/xmldsig#rsa-sha1 identifica uma assinatura RSA PKCS1 SHA-1. Devido a problemas de colisão com o SHA-1, a Microsoft recomenda um modelo de segurança baseado no SHA-256 ou superior. Este elemento é representado pela SignatureMethod propriedade.O
<SignatureValue>elementoEspecifica a assinatura criptográfica para o
<Signature>elemento. Se essa assinatura não for verificada, alguma parte do<Signature>bloco foi adulterada e o documento será considerado inválido. Desde que o<CanonicalizationMethod>valor seja confiável, esse valor é altamente resistente a adulterações. Este elemento é representado pela SignatureValue propriedade.O
URIatributo do<Reference>elementoEspecifica um objeto de dados usando uma referência de URI. Este atributo é representado pela Reference.Uri propriedade.
Não especificar o
URIatributo, ou seja, definir a Reference.Uri propriedade comonull, significa que se espera que o aplicativo recetor conheça a identidade do objeto. Na maioria dos casos, umnullURI resultará em uma exceção sendo lançada. Não use umnullURI, a menos que seu aplicativo esteja interoperando com um protocolo que o exija.Definir o
URIatributo como uma cadeia de caracteres vazia indica que o elemento raiz do documento está sendo assinado, uma forma de assinatura envelopada.Se o valor do
URIatributo começar com #, o valor deverá ser resolvido para um elemento no documento atual. Este formulário pode ser usado com qualquer um dos tipos de assinatura suportados (assinatura envelopada, assinatura envolvente ou assinatura separada interna).Qualquer outra coisa é considerada uma assinatura de recurso externo separada e não é suportada pela classe SignedXml.
O
<Transforms>elementoContém uma lista ordenada de elementos
<Transform>que descrevem como o signatário obteve o objeto de dados que foi processado. Um algoritmo de transformação é semelhante ao método de canonicalização, mas em vez de reescrever o<Signature>elemento, ele reescreve o conteúdo identificado peloURIatributo do<Reference>elemento. O<Transforms>elemento é representado pela TransformChain classe.Cada algoritmo de transformação é definido como tendo XML (um conjunto de nós XPath) ou bytes como entrada. Se o formato dos dados atuais for diferente dos requisitos de entrada da transformação, as regras de conversão serão aplicadas.
Cada algoritmo de transformação é definido como produzindo XML ou bytes como saída.
Se a saída do algoritmo da última transformação não estiver definida em bytes (ou nenhuma transformação tiver sido especificada), o método de canonicalização será usado como uma transformação implícita (mesmo que um algoritmo diferente tenha sido especificado no
<CanonicalizationMethod>elemento).Um valor de http://www.w3.org/2000/09/xmldsig#enveloped-signature para o algoritmo de transformação codifica uma regra que é interpretada como uma regra para remover o elemento
<Signature>do documento. Caso contrário, um verificador de uma assinatura envelopada digerirá o documento, incluindo a assinatura, mas o signatário teria digerido o documento antes de a assinatura ser aplicada, levando a respostas diferentes.
O
<DigestMethod>elementoIdentifica o método digest (hash criptográfico) a ser aplicado no conteúdo transformado identificado pelo atributo
URIdo elemento<Reference>. Isto é representado pela propriedade Reference.DigestMethod.
Escolhendo um método de canonicalização
A menos que interopere com uma especificação que exija o uso de um valor diferente, recomendamos que você use o método de canonicalização .NET padrão, que é o algoritmo XML-C14N 1.0, cujo valor é http://www.w3.org/TR/2001/REC-xml-c14n-20010315. O algoritmo XML-C14N 1.0 deve ser suportado por todas as implementações de XMLDSIG, especialmente porque é uma transformação final implícita a ser aplicada.
Existem versões de algoritmos de canonicalização que suportam a preservação de comentários. Métodos de canonicalização que preservam comentários não são recomendados porque violam o princípio de "assinar o que se vê". Ou seja, os comentários em um <Signature> elemento não alterarão a lógica de processamento de como a assinatura é executada, apenas qual é o valor da assinatura. Quando combinado com um algoritmo de assinatura fraco, permitir que os comentários sejam incluídos dá a um invasor liberdade desnecessária para forçar uma colisão de hash, fazendo com que um documento adulterado pareça legítimo. No .NET Framework, apenas canonicalizers internos são suportados por padrão. Para dar suporte a canonizadores adicionais ou personalizados, consulte a SafeCanonicalizationMethods propriedade. Se o documento usa um método de canonicalização que não está na coleção representada pela SafeCanonicalizationMethods propriedade, o CheckSignature método retornará false.
Observação
Um aplicativo extremamente defensivo pode remover quaisquer valores que não espera que os signatários usem da SafeCanonicalizationMethods coleção.
Os valores de referência estão protegidos contra adulteração?
Sim, os <Reference> valores estão protegidos contra adulteração. O .NET verifica o <SignatureValue> cálculo antes de processar qualquer um dos <Reference> valores e suas transformações associadas e interromperá precocemente para evitar instruções potencialmente mal-intencionadas.
Escolha os elementos a assinar
Recomendamos que você use o valor de "" para o URI atributo (ou defina a Uri propriedade como uma cadeia de caracteres vazia), se possível. Isso significa que todo o documento é considerado para o cálculo do resumo, o que significa que todo o documento está protegido contra adulteração.
É muito comum ver URI valores na forma de âncoras como #foo, referindo-se a um elemento cujo atributo ID é "foo". Infelizmente, é fácil que isso seja adulterado porque isso inclui apenas o conteúdo do elemento de destino, não o contexto. Abusar dessa distinção é conhecido como XML Signature Wrapping (XSW).
Se o seu aplicativo considera comentários semânticos (o que não é comum ao lidar com XML), então você deve usar "#xpointer(/)" em vez de "", e "#xpointer(id('foo'))" em vez de "#foo". As versões #xpointer são interpretadas como incluindo comentários, enquanto os formulários de nomes curtos excluem comentários.
Se você precisar aceitar documentos que estão apenas parcialmente protegidos e quiser garantir que está lendo o mesmo conteúdo que a assinatura protegeu, use o GetIdElement método.
Considerações de segurança sobre o elemento KeyInfo
Os dados no elemento opcional <KeyInfo> (ou seja, a KeyInfo propriedade), que contém uma chave para validar a assinatura, não devem ser confiáveis.
Em particular, quando o KeyInfo valor representa uma chave pública RSA, DSA ou ECDSA simples, o documento pode ter sido adulterado, apesar do CheckSignature método informar que a assinatura é válida. Isso pode acontecer porque a entidade que faz a adulteração só precisa gerar uma nova chave e assinar novamente o documento adulterado com essa nova chave. Assim, a menos que seu aplicativo verifique se a chave pública é um valor esperado, o documento deve ser tratado como se tivesse sido adulterado. Isso requer que seu aplicativo examine a chave pública incorporada no documento e verifique-a em relação a uma lista de valores conhecidos para o contexto do documento. Por exemplo, se o documento pudesse ser entendido como emitido por um usuário conhecido, você verificaria a chave em relação a uma lista de chaves conhecidas usadas por esse usuário.
Você também pode verificar a chave depois de processar o documento usando o CheckSignatureReturningKey método, em vez de usar o CheckSignature método. Mas, para a segurança ideal, você deve verificar a chave com antecedência.
Como alternativa, considere tentar as chaves públicas registradas do usuário, em vez de ler o que está no <KeyInfo> elemento .
Considerações de segurança sobre o elemento X509Data
O elemento opcional <X509Data> é filho do <KeyInfo> elemento e contém um ou mais certificados X509 ou identificadores para certificados X509. Os dados no <X509Data> elemento também não devem ser intrinsecamente confiáveis.
Ao verificar um documento com o elemento incorporado <X509Data> , o .NET verifica apenas se os dados são resolvidos para um certificado X509 cuja chave pública pode ser usada com êxito para validar a assinatura do documento. Ao contrário de quando se chama o método CheckSignature com o parâmetro verifySignatureOnly definido para false, nenhuma verificação de revogação é executada, nenhuma confiança de cadeia é confirmada e nenhuma expiração é verificada. Mesmo que a sua aplicação extraia o certificado necessário e o passe para o método CheckSignature com o parâmetro verifySignatureOnly configurado para false, isso ainda não é uma validação suficiente para evitar a adulteração de documentos. O certificado ainda precisa ser verificado como adequado para o documento que está sendo assinado.
O uso de um certificado de assinatura incorporado pode fornecer estratégias úteis de rotação de chaves, seja na <X509Data> seção ou no conteúdo do documento. Ao usar essa abordagem, um aplicativo deve extrair o certificado manualmente e executar uma validação semelhante a:
O certificado foi emitido diretamente ou através de uma cadeia por uma Autoridade de Certificação (CA) cujo certificado público está incorporado no aplicativo.
Usar a lista de confiança fornecida pelo SO sem verificações adicionais, como um nome de assunto conhecido, não é suficiente para impedir a adulteração do SignedXml.
Verifica-se que o certificado não expirou no momento da assinatura do documento (ou "agora" para processamento de documentos quase em tempo real).
Para certificados de longa duração emitidos por uma autoridade de certificação que ofereça suporte à revogação, verifique se o certificado não foi revogado.
O assunto do certificado é verificado como sendo apropriado para o documento atual.
Escolhendo o algoritmo de transformação
Se você estiver interoperando com uma especificação que tenha ditado valores específicos (como XrML), então você precisa seguir a especificação. Se você tiver uma assinatura envelopada (como ao assinar o documento inteiro), precisará usar http://www.w3.org/2000/09/xmldsig#enveloped-signature (representada pela XmlDsigEnvelopedSignatureTransform classe). Você também pode especificar a transformação implícita XML-C14N, mas não é necessário. Para uma assinatura envolvente ou destacada, não são necessárias transformações. Implícita, a transformação XML-C14N cuida de tudo.
Com a atualização de segurança introduzida pelo Boletim de Segurança da Microsoft MS16-035, o .NET restringiu quais transformações podem ser usadas na verificação de documentos por padrão, com transformações não confiáveis fazendo com CheckSignature que sempre retornem false. Em particular, transformações que exigem entrada adicional (especificadas como elementos filho no XML) não são mais permitidas devido à sua suscetibilidade de abuso por usuários mal-intencionados. O W3C aconselha evitar as transformações XPath e XSLT, que são as duas principais transformações afetadas por essas restrições.
O problema das referências externas
Se um aplicativo não verificar se as referências externas parecem apropriadas para o contexto atual, elas podem ser abusadas de maneiras que fornecem muitas vulnerabilidades de segurança (incluindo Negação de Serviço, Negação de Serviço de Reflexão Distribuída, Divulgação de Informações, Bypass de Assinatura e Execução Remota de Código). Mesmo que um aplicativo validasse o URI de referência externo, permaneceria um problema de o recurso ser carregado duas vezes: uma vez quando o aplicativo o lê e outra quando SignedXml o lê. Como não há garantia de que as etapas de leitura do aplicativo e verificação de documentos tenham o mesmo conteúdo, a assinatura não fornece confiabilidade.
Dados os riscos das referências externas, SignedXml lançará uma exceção quando uma referência externa for encontrada. Para mais informações sobre este problema, consulte aplicações do .NET Framework que encontram erros de exceção.