다음을 통해 공유


System.Security.Cryptography.Xml.SignedXml 클래스

이 문서는 이 API에 대한 참조 설명서를 보충하는 추가 설명을 제공합니다.

SignedXml 클래스는 XMLDSIG(XML 디지털 서명)라고도 하는 W3C(World Wide Web 컨소시엄) XML 서명 구문 및 처리 사양의 .NET 구현입니다. XMLDSIG는 XML 문서 또는 URI(Uniform Resource Identifier)에서 주소 지정이 가능한 다른 데이터의 전부 또는 일부를 서명하고 확인하는 표준 기반의 상호 운용 가능한 방법입니다.

SignedXml 표준 방식으로 애플리케이션 또는 조직 간에 서명된 XML 데이터를 공유해야 할 때마다 클래스를 사용합니다. 이 클래스를 사용하여 서명된 모든 데이터는 XMLDSIG에 대한 W3C 사양의 모든 준수 구현을 통해 확인할 수 있습니다.

SignedXml 클래스를 사용하면 다음과 같은 세 가지 종류의 XML 디지털 서명을 만들 수 있습니다.

서명 유형 설명
봉투 서명 서명은 서명되는 XML 요소 내에 포함됩니다.
서명 둘러싸기 서명된 XML은 요소 내에 <Signature> 포함됩니다.
내부 분리된 서명 서명 및 서명된 XML은 동일한 문서에 있지만 두 요소 모두 다른 요소를 포함하지 않습니다.

데이터와 서명이 별도의 XML 문서에 있는 경우 외부 분리된 서명이라는 네 번째 종류의 서명도 있습니다. 외부 분리된 서명은 클래스에서 SignedXml 지원되지 않습니다.

XML 서명의 구조

XMLDSIG는 XML 문서의 디지털 서명 또는 URI에서 주소 지정 가능한 기타 데이터를 포함하는 요소를 만듭니다 <Signature> . <Signature> 이 요소는 필요에 따라 서명을 확인할 키와 서명에 사용된 암호화 알고리즘에 대한 정보를 포함할 수 있습니다. 기본 구조는 다음과 같습니다.

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

이 구조의 주요 부분은 다음과 같습니다.

  • <CanonicalizationMethod> 요소

    서명 유효성 검사를 위해 XML/텍스트에서 바이트로 요소를 다시 쓰는 Signature 규칙을 지정합니다. .NET의 기본값은 http://www.w3.org/TR/2001/REC-xml-c14n-20010315신뢰할 수 있는 알고리즘을 식별하는 것입니다. 이 요소는 속성으로 SignedInfo.CanonicalizationMethod 표시됩니다.

  • <SignatureMethod> 요소

    서명 생성 및 유효성 검사에 사용되는 알고리즘을 지정하며, 이 알고리즘은 <Signature> 요소에 적용되어 <SignatureValue> 값이 생성됩니다. 이전 예제에서 값 http://www.w3.org/2000/09/xmldsig#rsa-sha1 은 RSA PKCS1 SHA-1 서명을 식별합니다. SHA-1의 충돌 문제로 인해 Microsoft는 SHA-256 이상에 기반한 보안 모델을 권장합니다. 이 요소는 속성으로 SignatureMethod 표시됩니다.

  • <SignatureValue> 요소

    요소에 대한 암호화 서명을 지정합니다 <Signature> . 이 서명이 확인되지 않으면 블록의 <Signature> 일부가 변조되었으며 문서가 잘못된 것으로 간주됩니다. 값이 <CanonicalizationMethod> 신뢰할 수 있는 한 이 값은 변조에 대한 강한 저항력이 있습니다. 이 요소는 속성으로 SignatureValue 표시됩니다.

  • URI 요소의 속성 <Reference>.

    URI 참조를 사용하여 데이터 개체를 지정합니다. 이 특성은 속성으로 Reference.Uri 표시됩니다.

    • 특성 URI을 지정하지 않으면, 즉 속성을 Reference.Urinull로 설정하면 수신 애플리케이션이 개체의 식별자를 알아야 합니다. 대부분의 경우 null URI로 인해 예외가 발생합니다. 애플리케이션이 null 필요한 프로토콜과 상호 운용하지 않는 한 URI를 사용하지 마세요.

    • URI 특성을 빈 문자열로 설정하면 문서의 루트 요소가 봉투 서명 형식으로 서명되고 있음을 나타냅니다.

    • 특성 값 URI 이 #으로 시작하는 경우 이 값은 현재 문서의 요소로 확인되어야 합니다. 이 양식은 지원되는 서명 형식(봉투형 서명, 둘러싸는 서명 또는 내부 분리된 서명)과 함께 사용할 수 있습니다.

    • 다른 항목은 외부 리소스 분리 서명으로 간주되며 클래스에서 SignedXml 지원되지 않습니다.

  • <Transforms> 요소

    서명자가 다이제스트된 데이터 개체를 가져온 방법을 설명하는 정렬된 요소 목록을 <Transform> 포함합니다. 변환 알고리즘은 정식화 메서드와 비슷하지만 요소를 다시 작성하는 <Signature> 대신 요소의 URI 특성으로 <Reference> 식별된 콘텐츠를 다시 작성합니다. <Transforms> 요소는 TransformChain 클래스로 표현됩니다.

    • 각 변환 알고리즘은 XML(XPath 노드 집합) 또는 바이트를 입력으로 사용하는 것으로 정의됩니다. 현재 데이터의 형식이 변환 입력 요구 사항과 다른 경우 변환 규칙이 적용됩니다.

    • 각 변환 알고리즘은 XML 또는 바이트를 출력으로 생성하는 것으로 정의됩니다.

    • 마지막 변환 알고리즘의 출력이 바이트로 정의되지 않았거나 변환이 지정되지 않은 경우 정식 화 메서드 는 암시적 변환으로 사용됩니다(요소에 <CanonicalizationMethod> 다른 알고리즘이 지정된 경우에도).

    • 변환 알고리즘의 http://www.w3.org/2000/09/xmldsig#enveloped-signature 값은 문서에서 요소를 제거하는 <Signature> 것으로 해석되는 규칙을 인코딩합니다. 그렇지 않으면 봉투형 서명의 검증 도구는 서명을 포함하여 문서를 다이제스트하겠지만, 서명자는 서명이 적용되기 전에 문서를 이미 다이제스트하여 결과가 다르게 나올 수 있습니다.

  • <DigestMethod> 요소

    변환된 콘텐츠에 적용할 다이제스트(암호화 해시) 메서드는 URI 요소의 <Reference> 특성에 의해 식별됩니다. 속성으로 Reference.DigestMethod 표시됩니다.

정식화 방법 선택

상호운용성이 요구되는 다른 값을 사용해야 하는 사양이 없는 경우, http://www.w3.org/TR/2001/REC-xml-c14n-20010315 값을 가지는 XML-C14N 1.0 알고리즘인 기본 .NET 정식화 메서드를 사용할 것을 권장합니다. XML-C14N 1.0 알고리즘은 특히 적용할 암시적 최종 변환이므로 XMLDSIG의 모든 구현에서 지원되어야 합니다.

주석 보존을 지원하는 정식화 알고리즘 버전이 있습니다. 주석 보존 정식화 메서드는 "표시되는 기호" 원칙을 위반하므로 권장되지 않습니다. 즉, 요소의 주석 <Signature> 은 서명이 수행되는 방식에 대한 처리 논리를 변경하지 않고 서명 값만 변경합니다. 약한 서명 알고리즘과 결합하여 주석을 포함할 수 있게 하면 공격자가 해시 충돌을 유도할 수 있는 불필요한 자유를 가질 수 있어 변조된 문서가 정당한 것으로 보이게 됩니다. .NET Framework에서는 기본적으로 기본 제공 정식 변환기만 지원됩니다. SafeCanonicalizationMethods 속성을 참조하여 추가 또는 사용자 정의 표준 변환기를 지원하세요. 정식화 메서드가 속성이 나타내는 컬렉션에 포함되지 않는 경우, 문서에서 SafeCanonicalizationMethods 메서드를 사용하면 CheckSignature 메서드는 false를 반환합니다.

비고

매우 방어적인 애플리케이션은 서명자가 컬렉션에서 SafeCanonicalizationMethods 사용할 것으로 예상하지 않는 값을 제거할 수 있습니다.

참조 값은 변조로부터 안전합니까?

예, 값은 <Reference> 변조로부터 안전합니다. .NET은 <SignatureValue> 값 및 관련 변환을 처리하기 전에 <Reference> 계산을 확인하고, 잠재적으로 악의적인 프로세싱 명령을 방지하기 위해 조기 중단합니다.

서명할 요소 선택

가능한 경우 URI 특성에 "" 값을 사용하거나 Uri 속성을 빈 문자열로 설정하라. 즉, 전체 문서가 다이제스트 계산에 고려됩니다. 즉, 전체 문서가 변조로부터 보호됩니다.

ID 특성이 "foo"인 요소를 참조하는 #foo 같은 앵커 형식의 값을 보는 URI 것은 매우 일반적입니다. 아쉽게도 컨텍스트가 아닌 대상 요소의 콘텐츠만 포함하므로 쉽게 변조할 수 있습니다. 이러한 구분을 악용하는 것을 XSW(XML 서명 래핑)라고 합니다.

애플리케이션에서 주석을 의미 체계(XML을 처리할 때 일반적이지 않음)로 간주하는 경우 "#foo" 대신 "#xpointer(/)" 및 "#xpointer(id('foo'))"를 사용해야 합니다. #xpointer 버전은 주석을 포함하는 것으로 해석되지만 짧은 이름 형식은 주석을 제외합니다.

부분적으로만 보호되는 문서를 수락해야 하며 서명이 보호한 것과 동일한 콘텐츠를 읽고 있는지 확인하려면 이 메서드를 GetIdElement 사용합니다.

KeyInfo 요소에 대한 보안 고려 사항

서명의 유효성을 검사하는 키가 포함된 선택적 <KeyInfo> 요소(즉, KeyInfo 속성)의 데이터는 신뢰할 수 없습니다.

특히 값이 KeyInfo 단순한 RSA, DSA 또는 ECDSA 공개 키를 나타내는 경우, CheckSignature 메서드가 서명이 유효하다고 보고하더라도 문서가 변조되었을 수 있습니다. 이는 변조를 수행하는 엔터티가 새 키를 생성하고 변조된 문서에 해당 새 키로 다시 서명해야 하기 때문에 발생할 수 있습니다. 따라서 애플리케이션에서 공개 키가 예상 값인지 확인하지 않는 한 문서가 변조된 것처럼 처리되어야 합니다. 이렇게 하려면 애플리케이션이 문서에 포함된 공개 키를 검사하고 문서 컨텍스트의 알려진 값 목록에 대해 확인해야 합니다. 예를 들어 알려진 사용자가 문서를 발급한 것으로 인식할 수 있는 경우 해당 사용자가 사용하는 알려진 키 목록에 대해 키를 확인합니다.

문서를 처리할 때 CheckSignatureReturningKey 메서드를 사용하는 대신, CheckSignature 메서드를 사용하여 키를 확인할 수도 있습니다. 그러나 최적의 보안을 위해 키를 미리 확인해야 합니다.

대신 <KeyInfo> 요소에 있는 내용을 읽지 않고 사용자의 등록된 공개 키를 시도해 보십시오.

X509Data 요소에 대한 보안 고려 사항

선택적 <X509Data> 요소는 요소의 <KeyInfo> 자식이며 X509 인증서에 대한 하나 이상의 X509 인증서 또는 식별자를 포함합니다. 요소의 <X509Data> 데이터도 본질적으로 신뢰할 수 없어야 합니다.

포함된 <X509Data> 요소를 사용하여 문서를 확인할 때 .NET은 공개 키를 사용하여 문서 서명의 유효성을 검사할 수 있는 X509 인증서로만 데이터가 확인되는지 확인합니다. 매개 변수가 CheckSignature으로 설정된 verifySignatureOnly 메서드를 호출하는 것과 달리, 해지 확인도 수행되지 않고 체인 신뢰도도 검사되지 않으며 만료도 확인되지 않습니다. 설사 애플리케이션이 인증서를 자체적으로 추출하여 CheckSignature 매개변수를 설정한 verifySignatureOnly 메서드에 false로 전달하더라도, 그것만으로는 문서 변조를 방지하기에 충분한 유효성 검사가 되지 않습니다. 인증서는 서명 중인 문서에 적합한 것으로 확인되어야 합니다.

포함된 서명 인증서를 사용하면 <X509Data> 섹션이든 문서 콘텐츠든 다양한 키 회전 전략을 제공할 수 있습니다. 이 방법을 사용하는 경우 애플리케이션은 인증서를 수동으로 추출하고 다음과 유사한 유효성 검사를 수행해야 합니다.

  • 인증서는 애플리케이션에 공용 인증서가 포함된 CA(인증 기관)에서 직접 또는 체인을 통해 발급되었습니다.

    추가 검사를 하지 않고, 예를 들어 알려진 주제 이름 같은, OS에서 제공하는 트러스트 목록만 사용하는 것은 SignedXml에서 변조를 방지하기에 충분하지 않습니다.

  • 인증서는 문서 서명 시 만료되지 않은 것으로 확인됩니다(또는 거의 실시간 문서 처리를 위해 "지금").

  • 해지를 지원하는 CA에서 발급한 수명이 긴 인증서의 경우 인증서가 해지되지 않은지 확인합니다.

  • 인증서 주체가 현재 문서에 적합한 것으로 확인되었습니다.

변환 알고리즘 선택

특정 값(예: XrML)을 지정한 사양과 상호 운용하는 경우 사양을 따라야 합니다. 만약 전체 문서에 서명하는 것과 같이 봉투 서명이 있을 경우, http://www.w3.org/2000/09/xmldsig#enveloped-signature 클래스로 표현된 XmlDsigEnvelopedSignatureTransform를 사용해야 합니다. 암시적 XML-C14N 변환도 지정할 수 있지만 필요하지는 않습니다. 포함된 또는 분리된 서명의 경우 변환이 필요하지 않습니다. 암시적 XML-C14N 변환은 모든 것을 처리합니다.

Microsoft 보안 게시판 MS16-035에서 도입된 보안 업데이트로 .NET은 기본적으로 문서 확인에 사용할 수 있는 변환을 제한했으며 신뢰할 수 없는 변환으로 인해 CheckSignature 항상 반환false됩니다. 특히 추가 입력이 필요한 변환(XML에서 자식 요소로 지정됨)은 악의적인 사용자에 의한 남용의 감수성으로 인해 더 이상 허용되지 않습니다. W3C는 이러한 제한의 영향을 받는 두 가지 주요 변환인 XPath 및 XSLT 변환을 방지하는 것이 좋습니다.

외부 참조 문제

애플리케이션에서 외부 참조가 현재 컨텍스트에 적합한 것으로 보이는지 확인하지 않으면 많은 보안 취약성(서비스 거부, 분산 리플렉션 서비스 거부, 정보 공개, 서명 바이패스 및 원격 코드 실행 포함)을 제공하는 방식으로 악용될 수 있습니다. 애플리케이션이 외부 참조 URI를 검증하려고 한다면, 리소스가 두 번 로드되는 문제가 여전히 남아 있습니다. 즉, 애플리케이션이 읽을 때 한 번, SignedXml가 참조할 때 한 번입니다. 애플리케이션 읽기 및 문서 확인 단계의 콘텐츠가 동일하다는 보장은 없으므로 서명은 신뢰성을 제공하지 않습니다.

외부 참조의 위험성 때문에 SignedXml가 외부 참조를 발견하면 예외를 발생시킵니다. 이 문제에 대한 자세한 내용은 KB 문서 3148821 참조하세요.