다음을 통해 공유


데이터에 대한 보안 고려 사항

WCF(Windows Communication Foundation)에서 데이터를 처리할 때는 여러 가지 위협 범주를 고려해야 합니다. 다음 목록에서는 데이터 처리와 관련된 가장 중요한 위협 클래스를 보여 줍니다. WCF는 이러한 위협을 완화하는 도구를 제공합니다.

  • 서비스 거부

    신뢰할 수 없는 데이터를 받을 때 데이터는 수신 측이 긴 계산을 발생시켜 메모리, 스레드, 사용 가능한 연결 또는 프로세서 주기와 같은 다양한 리소스의 불균형한 양에 액세스하게 할 수 있습니다. 서버에 대한 서비스 거부 공격으로 인해 충돌이 발생하고 다른 합법적인 클라이언트의 메시지를 처리할 수 없습니다.

  • 악성 코드 실행

    신뢰할 수 없는 데이터를 수신하면 수신 쪽에서 의도하지 않은 코드를 실행하게 됩니다.

  • 정보 공개

    원격 공격자는 수신 당사자가 의도한 것보다 더 많은 정보를 공개하는 방식으로 요청에 응답하도록 강제합니다.

User-Provided 코드 및 코드 액세스 보안

WCF(Windows Communication Foundation) 인프라의 여러 위치에서 사용자가 제공하는 코드를 실행합니다. 예를 들어 serialization 엔진은 DataContractSerializer 사용자가 제공한 속성 set 접근자 및 get 접근자를 호출할 수 있습니다. WCF 채널 인프라는 Message 클래스에서 파생된 사용자가 제공한 클래스들에 호출할 수 있습니다.

보안 취약성이 없도록 하는 것은 코드 작성자의 책임입니다. 예를 들어 정수 형식의 데이터 멤버 속성을 사용하여 데이터 계약 형식을 만들고 접근자 구현에서 set 속성 값을 기반으로 배열을 할당하는 경우 악의적인 메시지에 이 데이터 멤버에 대해 매우 큰 값이 포함된 경우 서비스 거부 공격의 가능성이 노출됩니다. 일반적으로 들어오는 데이터 또는 사용자 제공 코드의 긴 처리에 따라 할당을 피합니다(특히 들어오는 데이터의 양이 적기 때문에 긴 처리가 발생할 수 있는 경우). 사용자가 제공한 코드의 보안 분석을 수행할 때는 모든 오류 사례(즉, 예외가 throw되는 모든 코드 분기)도 고려해야 합니다.

사용자 제공 코드의 궁극적인 예는 각 작업에 대한 서비스 구현 내의 코드입니다. 서비스 구현의 보안은 사용자의 책임입니다. 서비스 거부 취약성을 초래할 수 있는 안전하지 않은 작업 구현을 실수로 쉽게 만들 수 있습니다. 예를 들어 문자열을 사용하고 이름이 해당 문자열로 시작하는 데이터베이스의 고객 목록을 반환하는 작업입니다. 큰 데이터베이스로 작업 중이고 전달되는 문자열이 단일 문자일 경우 코드에서 사용 가능한 모든 메모리보다 큰 메시지를 만들려고 시도하여 전체 서비스가 실패할 수 있습니다. (. OutOfMemoryException NET Framework에서는 복구할 수 없으며 항상 애플리케이션이 종료됩니다.)

악성 코드가 다양한 확장성 지점에 연결되어 있지 않은지 확인해야 합니다. 부분 신뢰에서 실행하거나, 부분적으로 신뢰할 수 있는 어셈블리의 형식을 처리하거나, 부분적으로 신뢰할 수 있는 코드에서 사용할 수 있는 구성 요소를 만들 때 특히 관련이 있습니다. 자세한 내용은 이후 섹션에서 "부분 신뢰 위협"을 참조하세요.

부분 신뢰에서 실행될 때, 데이터 계약 직렬화 인프라는 데이터 계약 프로그래밍 모델의 제한된 일부 기능만을 지원합니다. 예를 들어, SerializableAttribute 특성을 사용하는 프라이빗 데이터 멤버나 형식은 지원되지 않습니다. 자세한 내용은 부분 신뢰(Partial Trust)를 참조하세요.

비고

CAS(코드 액세스 보안)는 .NET Framework 및 .NET의 모든 버전에서 더 이상 사용되지 않습니다. 최신 버전의 .NET은 CAS 주석을 준수하지 않으며 CAS 관련 API를 사용하는 경우 오류가 발생합니다. 개발자는 보안 작업을 수행하는 대체 수단을 찾아야 합니다.

의도하지 않은 정보 공개 방지

보안을 염두에 두고 직렬화 가능한 형식을 디자인할 때 정보 공개가 가능한 문제입니다.

다음 사항을 고려합니다.

  • DataContractSerializer 프로그래밍 모델을 사용하면 serialization 중에 형식 또는 어셈블리 외부의 프라이빗 및 내부 데이터를 노출할 수 있습니다. 또한 스키마를 내보내는 동안 형식의 모양을 노출할 수 있습니다. 자신의 형식의 직렬화 투영을 이해해야 합니다. 아무것도 노출하지 않으려면 serialize를 사용하지 않도록 설정합니다(예: 데이터 계약의 경우 특성을 적용 DataMemberAttribute 하지 않음).

  • 사용 중인 serializer에 따라 동일한 형식에 여러 개의 직렬화 방식이 존재할 가능성이 있습니다. 동일한 형식은 한 데이터 집합과 함께 사용할 때 데이터 집합을 DataContractSerializer 표시하고, 다른 데이터 집합과 함께 사용할 경우 다른 데이터 집합을 노출할 XmlSerializer수 있습니다. 실수로 잘못된 serializer를 사용하면 정보가 공개됩니다.

  • XmlSerializer 레거시 RPC(원격 프로시저 호출)/인코딩 모드를 사용하면 보내는 쪽에 있는 개체 그래프의 모양을 수신측에 의도치 않게 노출할 수 있습니다.

서비스 거부 공격 방지

할당량

수신 측에서 상당한 양의 메모리를 할당하도록 하는 것은 잠재적인 서비스 거부 공격입니다. 이 섹션에서는 큰 메시지에서 발생하는 메모리 사용 문제에 집중하지만 다른 공격이 발생할 수 있습니다. 예를 들어 메시지에는 불균형한 처리 시간이 사용될 수 있습니다.

서비스 거부 공격은 일반적으로 할당량을 사용하여 완화됩니다. 할당량을 초과하면 일반적으로 예외가 QuotaExceededException 발생합니다. 할당량이 없으면 악의적인 메시지로 인해 사용 가능한 모든 메모리에 액세스하게 되어 OutOfMemoryException 예외가 발생하거나, 사용 가능한 모든 스택에 액세스하게 되어 StackOverflowException 예외가 발생할 수 있습니다.

할당량 초과 시나리오를 복구할 수 있습니다. 실행 중인 서비스에서 발견되면 현재 처리 중인 메시지가 삭제되고 서비스가 계속 실행되고 추가 메시지가 처리됩니다. 그러나 메모리 부족 및 스택 오버플로 시나리오는 .NET Framework의 어느 곳에서도 복구할 수 없습니다. 이러한 예외가 발생하면 서비스가 종료됩니다.

WCF의 할당량에는 사전 할당이 포함되지 않습니다. 예를 들어 다양한 클래스에 있는 할당량이 128KB로 설정된 경우 MaxReceivedMessageSize 각 메시지에 대해 128KB가 자동으로 할당된다는 의미는 아닙니다. 할당된 실제 크기는 들어오는 실제 메시지 크기에 따라 달라집니다.

많은 할당량은 전송 계층에서 사용할 수 있습니다. 이는 사용 중인 특정 전송 채널(HTTP, TCP 등)에 의해 적용되는 할당량입니다. 이 항목에서는 이러한 할당량 중 일부에 대해 설명하지만 이러한 할당량은 전송 할당량에 자세히 설명 되어 있습니다.

해시 테이블 취약성

데이터 계약에 해시 테이블 또는 컬렉션이 포함된 경우 취약성이 존재합니다. 많은 수의 값이 동일한 해시 값을 생성하는 해시 테이블로 많은 수의 값이 삽입되는 경우 문제가 발생합니다. DOS 공격으로 사용할 수 있습니다. MaxReceivedMessageSize 바인딩 할당량을 설정하여 이 취약성을 완화할 수 있습니다. 이러한 공격을 방지하려면 이 할당량을 설정하는 동안 주의해야 합니다. 이 할당량은 WCF 메시지의 크기에 상한을 붙입니다. 또한 데이터 계약에서 해시 테이블 또는 컬렉션을 사용하지 않도록 합니다.

스트리밍 없이 메모리 사용 제한

대용량 메시지의 보안 모델은 스트리밍이 사용 중인지 여부에 따라 달라집니다. 스트리밍되지 않는 기본 사례에서는 메시지가 메모리에 버퍼링됩니다. 이 경우 MaxReceivedMessageSize 할당량을 TransportBindingElement 또는 시스템 제공 바인딩에 사용하여 접근 가능한 최대 메시지 크기를 제한함으로써 큰 메시지로부터 보호합니다. 서비스가 동시에 여러 메시지를 처리할 수 있으며, 이 경우 모두 메모리에 있습니다. 제한 기능을 사용하여 이 위협을 완화합니다.

MaxReceivedMessageSize 또한 메시지당 메모리 사용량에 상한을 두지 않고 상수 요소 내로 제한합니다. 예를 들어 1MB이고 1MB 메시지가 수신된 다음 역직렬화된 경우 MaxReceivedMessageSize 역직렬화된 개체 그래프를 포함하려면 추가 메모리가 필요하므로 총 메모리 사용량이 1MB를 초과합니다. 이러한 이유로 들어오는 데이터가 많지 않은 경우 상당한 메모리 소비를 초래할 수 있는 직렬화 가능 형식을 만들지 마십시오. 예를 들어 50개의 선택적 데이터 멤버 필드와 추가로 100개의 프라이빗 필드가 있는 데이터 계약 "MyContract"를 XML 생성 "<MyContract/>"로 인스턴스화할 수 있습니다. 이 XML을 사용하면 150개 필드에 대한 메모리에 액세스할 수 있습니다. 데이터 멤버는 기본적으로 선택 사항입니다. 이러한 형식이 배열의 일부인 경우 문제가 복잡해집니다.

MaxReceivedMessageSize 서비스 거부 공격만으로는 충분하지 않습니다. 예를 들어, 들어오는 메시지로 인해 다른 개체를 포함하고 있는 개체가 다시 또 다른 개체를 포함하는 식의 깊게 중첩된 객체 그래프를 역직렬화해야 할 수 있습니다. 이러한 그래프를 DataContractSerializerXmlSerializer 역직렬화하는 중첩된 방식으로 메서드를 호출합니다. 메서드 호출의 심한 중첩은 복구 불가능한 StackOverflowException로 이어질 수 있습니다. 이 위협은 항목의 뒷부분에 MaxDepth 있는 "XML 안전 사용" 섹션에서 설명한 대로 할당량을 설정하여 XML 중첩 수준을 제한하여 완화됩니다.

이진 XML 인코딩을 MaxReceivedMessageSize 사용하는 경우 추가 할당량을 설정하는 것이 특히 중요합니다. 이진 인코딩을 사용하는 것은 압축과 다소 동일합니다. 들어오는 메시지의 작은 바이트 그룹은 많은 데이터를 나타낼 수 있습니다. 따라서 제한에 MaxReceivedMessageSize 맞는 메시지조차도 완전히 확장된 형태로 훨씬 더 많은 메모리를 차지할 수 있습니다. 이러한 XML 관련 위협을 완화하려면 이 항목의 뒷부분에 있는 "안전한 XML 사용" 섹션에서 설명한 대로 모든 XML 판독기 할당량을 올바르게 설정해야 합니다.

스트리밍을 사용하여 메모리 사용 제한

스트리밍할 때 작은 MaxReceivedMessageSize 설정을 사용하여 서비스 거부 공격으로부터 보호할 수 있습니다. 그러나 스트리밍에서는 더 복잡한 시나리오가 가능합니다. 예를 들어 파일 업로드 서비스는 사용 가능한 모든 메모리보다 큰 파일을 허용합니다. 이 경우 메모리에 버퍼링된 데이터가 거의 없고 메시지가 디스크로 직접 스트림될 것으로 예상하여 매우 큰 값으로 설정합니다 MaxReceivedMessageSize . 악의적인 메시지가 이 경우 MaxReceivedMessageSize 데이터를 스트리밍하는 대신 WCF에서 데이터를 버퍼링하도록 강제할 수 있는 경우 더 이상 사용 가능한 모든 메모리에 액세스하는 메시지로부터 보호하지 않습니다.

이러한 위협을 완화하기 위해 버퍼링을 제한하는 다양한 WCF 데이터 처리 구성 요소에 특정 할당량 설정이 있습니다. 이 중 가장 중요한 것은 MaxBufferSize 다양한 전송 바인딩 요소 및 표준 바인딩에 대한 속성입니다. 스트리밍할 때 메시지당 할당하려는 최대 메모리 양을 고려하여 이 할당량을 설정해야 합니다. 마찬가지로 MaxReceivedMessageSize, 설정은 메모리 사용량에 절대 최대값을 두지 않고 상수 요소 내에서만 제한합니다. 또한 마찬가지로 MaxReceivedMessageSize여러 메시지가 동시에 처리될 수 있다는 점에 유의하세요.

MaxBufferSize 세부 정보

이 속성은 MaxBufferSize WCF가 수행하는 모든 대량 버퍼링을 제한합니다. 예를 들어 WCF는 항상 SOAP 헤더 및 SOAP 오류를 버퍼링하고 MTOM(메시지 전송 최적화 메커니즘) 메시지에서 자연 읽기 순서가 아닌 것으로 확인된 MIME 부분을 버퍼링합니다. 이 설정은 이러한 모든 경우에 버퍼링의 양을 제한합니다.

WCF는 버퍼링할 수 있는 다양한 구성 요소에 값을 전달 MaxBufferSize 하여 이 작업을 수행합니다. 예를 들어 CreateMessage 클래스의 일부 Message 오버로드는 maxSizeOfHeaders 매개 변수를 가집니다. WCF는 MaxBufferSize SOAP 헤더 버퍼링의 양을 제한하기 위해 이 매개 변수에 값을 전달합니다. 클래스를 직접 사용할 때는 이 매개 변수를 Message 설정하는 것이 중요합니다. 일반적으로 할당량 매개 변수를 사용하는 WCF의 구성 요소를 사용하는 경우 이러한 매개 변수의 보안 영향을 이해하고 올바르게 설정하는 것이 중요합니다.

MTOM 메시지 인코더에도 설정이 있습니다 MaxBufferSize . 표준 바인딩을 사용하는 경우 전송 수준 MaxBufferSize 값으로 자동으로 설정됩니다. 그러나 MTOM 메시지 인코더 바인딩 요소를 사용하여 사용자 지정 바인딩을 생성하는 경우 스트리밍을 사용할 때 속성을 안전한 값으로 설정하는 MaxBufferSize 것이 중요합니다.

스트리밍 공격 XML-Based

MaxBufferSize 스트리밍이 예상될 때 WCF를 버퍼링으로 강제 적용할 수 없도록 하는 것만으로는 충분하지 않습니다. 예를 들어 WCF XML 판독기는 새 요소를 읽기 시작할 때 항상 전체 XML 요소 시작 태그를 버퍼링합니다. 이 작업은 네임스페이스와 특성이 제대로 처리되도록 수행됩니다. 만약 MaxReceivedMessageSize가 크게 구성된 경우(예: 직접 디스크에 대용량 파일 스트리밍 시나리오를 사용하도록 설정), 전체 메시지 본문이 큰 XML 요소 시작 태그로 구성된 악의적인 메시지가 생성될 수 있습니다. 읽으려고 시도하면 OutOfMemoryException 오류가 발생합니다. 이는 이 항목의 뒷부분에 있는 "XML 안전 사용" 섹션에서 설명한 XML 판독기 할당량을 사용하여 모두 완화할 수 있는 여러 가능한 XML 기반 서비스 거부 공격 중 하나입니다. 스트리밍할 때는 이러한 할당량을 모두 설정하는 것이 특히 중요합니다.

스트리밍 및 버퍼링 프로그래밍 모델 혼합

동일한 서비스에서 스트리밍 및 비 스트리밍 프로그래밍 모델을 혼합하여 많은 공격이 발생할 수 있습니다. 서비스 계약에 두 개의 작업이 있다고 가정해 보겠습니다. 하나는 Stream를 받고, 다른 하나는 사용자 지정 형식의 배열을 받습니다. 또한 MaxReceivedMessageSize 첫 번째 작업이 큰 스트림을 처리할 수 있도록 큰 값으로 설정한다고 가정합니다. 아쉽게도 이제 큰 메시지를 두 번째 작업으로 보낼 수 있으며 역직렬 변환기는 작업을 호출하기 전에 메모리의 데이터를 배열로 버퍼링합니다. 이는 잠재적 서비스 거부 공격입니다. 할당량은 MaxBufferSize 역직렬 변환기가 작동하는 메시지 본문의 크기를 제한하지 않습니다.

따라서 동일한 계약에서 스트림 기반 작업과 스트리밍되지 않은 작업을 혼합하지 않습니다. 두 프로그래밍 모델을 반드시 혼합해야 하는 경우 다음 주의 사항을 사용합니다.

  • IExtensibleDataObject 기능을 끄려면 IgnoreExtensionDataObjectServiceBehaviorAttribute 속성을 true으로 설정하십시오. 이렇게 하면 계약의 일부인 멤버만 역직렬화됩니다.

  • 안전 MaxItemsInObjectGraph 값으로 DataContractSerializer 속성을 설정합니다. 이 할당량은 ServiceBehaviorAttribute 특성 또는 구성을 통해서도 사용할 수 있습니다. 이 할당량은 하나의 역직렬화 에피소드에서 역직렬화되는 개체의 수를 제한합니다. 일반적으로 메시지 계약의 각 작업 매개 변수 또는 메시지 본문 부분은 한 에피소드에서 역직렬화됩니다. 배열을 역직렬화할 때 각 배열 항목은 별도의 개체로 계산됩니다.

  • 모든 XML 판독기 할당량을 안전한 값으로 설정합니다. MaxDepth, MaxStringContentLength, MaxArrayLength에 주의를 기울이고 비스트리밍 작업에서 문자열을 피하십시오.

  • 알려진 형식 목록을 검토하여 언제든지 인스턴스화할 수 있습니다(이 항목의 뒷부분에 있는 "의도하지 않은 형식 로드 방지" 섹션 참조).

  • 많은 데이터를 버퍼링하는 인터페이스를 IXmlSerializable 구현하는 형식은 사용하지 마세요. 이러한 형식을 알려진 형식 목록에 추가하지 마세요.

  • 계약에서 구현 XmlElement 하는 XmlNode, Byte 배열, ISerializable 배열 또는 형식을 사용하지 마세요.

  • 알려진 형식 목록에서 XmlElement 배열, XmlNode 배열, Byte 배열, 또는 ISerializable를 구현하는 형식을 사용하지 마세요.

위의 주의 사항은 스트리밍되지 않은 작업이 .를 사용하는 경우에 적용됩니다 DataContractSerializer. 동일한 서비스에서 XmlSerializer를 사용하는 경우, MaxItemsInObjectGraph 할당량의 보호가 없으므로 스트리밍 및 비스트리밍 프로그래밍 모델을 혼합하지 마세요.

느린 스트림 공격

스트리밍 서비스 거부 공격의 클래스에는 메모리 사용이 포함되지 않습니다. 대신, 공격은 데이터를 느리게 보내는 서버 또는 수신자를 포함합니다. 데이터를 보내거나 받을 때까지 기다리는 동안 스레드 및 사용 가능한 연결과 같은 리소스가 소진됩니다. 이 상황은 악의적인 공격의 결과로 발생하거나 느린 네트워크 연결에서 합법적인 보낸 사람/수신자에서 발생할 수 있습니다.

이러한 공격을 완화하려면 전송 시간 초과를 올바르게 설정합니다. 자세한 내용은 전송 할당량을 참조하세요. 둘째, WCF에서 스트림을 사용할 때 동기 Read 또는 Write 작업을 사용하지 마세요.

XML을 안전하게 사용

비고

이 섹션은 XML에 관한 것이지만 JSON(JavaScript Object Notation) 문서에도 정보가 적용됩니다. 할당량은 JSON과 XML 간의 매핑을 사용하여 비슷하게 작동합니다.

보안 XML 판독기

XML Infoset은 WCF에서 모든 메시지 처리의 기초를 형성합니다. 신뢰할 수 없는 원본에서 XML 데이터를 수락하는 경우 완화해야 하는 여러 가지 서비스 거부 공격 가능성이 있습니다. WCF는 특별하고 안전한 XML 판독기를 제공합니다. 이러한 판독기는 WCF(텍스트, 이진 또는 MTOM)의 표준 인코딩 중 하나를 사용할 때 자동으로 만들어집니다.

이러한 판독기의 보안 기능 중 일부는 항상 활성화되어 있습니다. 예를 들어 판독기는 서비스 거부 공격의 잠재적 원인이며 합법적인 SOAP 메시지에 표시되지 않아야 하는 DTD(문서 형식 정의)를 처리하지 않습니다. 다른 보안 기능에는 다음 섹션에 설명된 구성해야 하는 판독기 할당량이 포함됩니다.

XML 판독기를 직접 사용할 때(예: 사용자 지정 인코더를 작성하거나 클래스로 Message 직접 작업할 때) 신뢰할 수 없는 데이터로 작업할 가능성이 있는 경우 항상 WCF 보안 판독기를 사용합니다. CreateTextReader 클래스의 정적 팩터리 메서드 오버로드 CreateBinaryReader, CreateMtomReader, 또는 XmlDictionaryReader 중 하나를 호출하여 보안 판독기를 만듭니다. 판독기를 만들 때 보안 할당량 값을 전달합니다. 오버로드된 메서드를 Create 호출하지 마세요. 이러한 것들은 WCF 리더를 생성하지 않습니다. 대신 이 섹션에 설명된 보안 기능으로 보호되지 않는 판독기를 만듭니다.

읽기 권한자 할당량

보안 XML 판독기는 5개의 구성 가능한 할당량을 갖습니다. 이는 일반적으로 인코딩 바인딩 요소나 표준 바인딩의 ReaderQuotas 속성을 사용하거나, 리더를 생성할 때 전달되는 XmlDictionaryReaderQuotas 객체를 사용하여 구성됩니다.

최대 읽기 바이트 수

이 할당량은 요소 시작 태그 및 해당 특성을 읽을 때 단일 Read 작업에서 읽는 바이트 수를 제한합니다. (스트리밍되지 않은 경우 요소 이름 자체는 할당량에 대해 계산되지 않습니다.) MaxBytesPerRead 는 다음과 같은 이유로 중요합니다.

  • 요소 이름과 해당 특성은 읽을 때 항상 메모리에 버퍼링됩니다. 따라서 스트리밍이 예상되는 경우 과도한 버퍼링을 방지하기 위해 스트리밍 모드에서 이 할당량을 올바르게 설정하는 것이 중요합니다. MaxDepth 발생하는 실제 버퍼링 양에 대한 자세한 내용은 할당량 섹션을 참조하세요.

  • XML 특성이 너무 많으면 특성 이름이 고유성을 확인해야 하므로 처리 시간이 너무 많이 소요될 수 있습니다. MaxBytesPerRead 는 이 위협을 완화합니다.

최대 깊이

이 할당량은 XML 요소의 최대 중첩 깊이를 제한합니다. 예를 들어 문서 "<A><B><C/></B></A>"의 중첩 깊이는 3입니다. MaxDepth 는 다음과 같은 이유로 중요합니다.

  • MaxDepthMaxBytesPerRead상호 작용: 판독기는 항상 현재 요소 및 모든 상위 항목에 대한 메모리에 데이터를 유지하므로 판독기의 최대 메모리 사용량은 이러한 두 설정의 곱에 비례합니다.

  • 깊이 중첩된 개체 그래프를 역직렬화하는 과정에서, 역직렬 변환기는 전체 스택에 액세스하고 복구할 수 없는 StackOverflowException를 발생시켜야 합니다. XML 중첩과 개체 중첩 간에는 둘 다 DataContractSerializerXmlSerializer에 대한 직접적인 상관 관계가 있습니다. MaxDepth을(를) 사용하여 이 위협을 완화하세요.

MaxNameTableCharCount

이 할당량은 판독기의 네임테이블 크기를 제한합니다. 이름 파일에는 XML 문서를 처리할 때 발생하는 특정 문자열(예: 네임스페이스 및 접두사)이 포함됩니다. 이러한 문자열은 메모리에 버퍼링되므로 스트리밍이 예상되는 경우 과도한 버퍼링을 방지하도록 이 할당량을 설정합니다.

MaxStringContentLength

이 할당량은 XML 판독기에서 반환하는 최대 문자열 크기를 제한합니다. 이 할당량은 XML 판독기 자체가 아니라 판독기를 사용하는 구성 요소에서 메모리 사용을 제한하지 않습니다. 예를 들어 보호된 DataContractSerializer판독기를 사용하는 경우 MaxStringContentLength 이 할당량보다 큰 문자열을 역직렬화하지 않습니다. 클래스를 XmlDictionaryReader 직접 사용하는 경우 모든 메서드가 이 할당량을 준수하는 것은 아니지만 메서드와 같은 ReadContentAsString 문자열을 읽도록 특별히 설계된 메서드만을 사용합니다. 판독기 속성은 Value 이 할당량의 영향을 받지 않으므로 이 할당량이 제공하는 보호가 필요한 경우 사용하면 안 됩니다.

최대배열길이

이 할당량은 바이트 배열을 포함하여 XML 판독기에서 반환하는 기본 형식 배열의 최대 크기를 제한합니다. 이 할당량은 XML 판독기 자체가 아니라 판독기를 사용하는 구성 요소에서 메모리 사용을 제한하지 않습니다. 예를 들어 보호된 DataContractSerializer판독기를 사용하는 경우 MaxArrayLength 이 할당량보다 큰 바이트 배열을 역직렬화하지 않습니다. 단일 계약에서 스트리밍 및 버퍼링된 프로그래밍 모델을 혼합하려고 할 때 이 할당량을 설정하는 것이 중요합니다. 클래스를 XmlDictionaryReader 직접 사용하는 경우 특정 기본 형식 ReadInt32Array의 임의 크기의 배열을 읽도록 특별히 설계된 메서드만 이 할당량을 준수합니다.

이진 인코딩과 관련된 위협

이진 XML 인코딩 WCF는 사전 문자열 기능을 포함합니다. 큰 문자열은 몇 바이트만 사용하여 인코딩할 수 있습니다. 이렇게 하면 상당한 성능 향상이 가능하지만 완화해야 하는 새로운 서비스 거부 위협이 발생합니다.

사전의 두 종류가 있습니다: 정적동적. 정적 사전은 이진 인코딩의 짧은 코드를 사용하여 나타낼 수 있는 긴 문자열의 기본 제공 목록입니다. 이 문자열 목록은 판독기를 만들 때 수정되며 수정할 수 없습니다. WCF에서 기본적으로 사용하는 정적 사전의 문자열 중 어느 것도 사전 확장 공격에 여전히 사용될 수 있지만 심각한 서비스 거부 위협을 제기하기에는 충분히 크지 않습니다. 고유한 정적 사전을 제공하는 고급 시나리오에서는 큰 사전 문자열을 도입할 때 주의해야 합니다.

동적 사전 기능을 사용하면 메시지가 자체 문자열을 정의하고 짧은 코드와 연결할 수 있습니다. 이러한 문자열-코드 매핑은 전체 통신 세션 동안 메모리에 유지됩니다. 따라서 후속 메시지는 문자열을 다시 전송할 필요가 없으며 이미 정의된 코드를 활용할 수 있습니다. 이러한 문자열은 임의의 길이일 수 있으므로 정적 사전의 문자열보다 더 심각한 위협이 될 수 있습니다.

완화해야 하는 첫 번째 위협은 동적 사전(문자열-코드 매핑 테이블)이 너무 커질 가능성이 있다는 것입니다. 이 사전은 여러 메시지 과정에서 확장될 수 있으므로 MaxReceivedMessageSize 할당량은 각 메시지에만 개별적으로 적용되므로 보호를 제공하지 않습니다. 따라서 사전의 크기를 제한하는 별도의 MaxSessionSize 속성이 있습니다 BinaryMessageEncodingBindingElement .

대부분의 다른 할당량과 달리 이 할당량은 메시지를 작성할 때도 적용됩니다. 메시지를 읽을 때 이 값을 QuotaExceededException 초과하면 평소와 같이 throw됩니다. 메시지를 작성할 때 초과된 경우 할당량을 초과하는 문자열은 동적 사전 기능을 사용하지 않고 as-is기록됩니다.

사전 확장 위협

이진 특정 공격의 중요한 유형은 사전 확장에서 발생합니다. 이진 형식의 작은 메시지는 문자열 사전 기능을 광범위하게 사용하는 경우 완전히 확장된 텍스트 형식의 매우 큰 메시지로 바뀔 수 있습니다. 동적 사전 문자열의 확장 요소는 전체 사전의 MaxSessionSize 최대 크기를 초과하는 동적 사전 문자열이 없으므로 할당량에 의해 제한됩니다.

, MaxNameTableCharCountMaxStringContentLength 속성은 MaxArrayLength메모리 사용량만 제한합니다. 일반적으로 메모리 사용량이 이미 제한 MaxReceivedMessageSize되므로 스트리밍되지 않은 사용량의 위협을 완화할 필요가 없습니다. 그러나 MaxReceivedMessageSize 확장 전 바이트를 계산합니다. 이진 인코딩이 사용 중인 경우 메모리 사용량이 잠재적으로 초과될 MaxReceivedMessageSize수 있으며, 이는 한 요소 MaxSessionSize에 의해서만 제한됩니다. 이러한 이유로 이진 인코딩을 사용하는 경우 항상 모든 판독기 할당량(특히 MaxStringContentLength)을 설정하는 것이 중요합니다.

이진 인코딩을 DataContractSerializer와 함께 사용할 때, IExtensibleDataObject 인터페이스를 오용하여 사전 확장 공격을 수행할 수 있습니다. 이 인터페이스는 기본적으로 계약의 일부가 아닌 임의 데이터에 대한 무제한 스토리지를 제공합니다. 할당량을 MaxSessionSizeMaxReceivedMessageSize의 곱이 문제가 되지 않을 정도로 충분히 낮게 설정할 수 없는 경우, 이진 인코딩을 사용할 때 IExtensibleDataObject 기능을 비활성화하십시오. IgnoreExtensionDataObject 속성을 true 속성의 ServiceBehaviorAttribute로 설정합니다. 또는 인터페이스를 IExtensibleDataObject 구현하지 마세요. 자세한 내용은 Forward-Compatible 데이터 계약을 참조하세요.

할당량 요약

다음 표에서는 할당량에 대한 지침을 요약합니다.

조건 설정할 중요한 할당량
스트리밍 금지 및 작은 메시지, 텍스트 또는 MTOM 인코딩 차단하기 MaxReceivedMessageSize, MaxBytesPerReadMaxDepth
스트리밍 없음 또는 작은 메시지 스트리밍, 이진 인코딩 MaxReceivedMessageSize, MaxSessionSize 및 모든 ReaderQuotas
대용량 메시지, 텍스트 또는 MTOM 인코딩의 스트리밍 MaxBufferSize 및 모두 ReaderQuotas
큰 메시지 스트리밍, 이진 인코딩 MaxBufferSize, MaxSessionSize 및 모든 ReaderQuotas
  • 전송 수준 제한 시간은 대용량 또는 작은 메시지를 스트리밍하는지 여부에 관계없이 스트리밍이 사용 중일 때 항상 설정되어야 하며 동기 읽기/쓰기를 사용하지 않아야 합니다.

  • 할당량에 대해 의심스러운 경우 할당량을 열어 두지 않고 안전한 값으로 설정합니다.

악성 코드 실행 방지

다음과 같은 일반적인 위협 클래스는 코드를 실행하고 의도하지 않은 영향을 미칠 수 있습니다.

  • 역직렬 변환기는 악의적이거나 안전하지 않거나 보안상 민감한 유형을 로드합니다.

  • 들어오는 메시지가 역직렬 변환기로 하여금 보통 안전한 유형의 인스턴스를 예기치 않은 결과를 낳을 방식으로 생성하게 만듭니다.

다음 섹션에서는 이러한 위협 클래스에 대해 자세히 설명합니다.

DataContractSerializer

(보안 관련 정보는 XmlSerializer 관련 설명서를 참조하세요.) XmlSerializer의 보안 모델은 DataContractSerializer과 유사하며, 주로 세부사항에서 차이가 있습니다. 예를 들어 XmlIncludeAttribute 특성은 KnownTypeAttribute 특성 대신 형식 포함에 사용됩니다. XmlSerializer에 고유한 일부 위협은 이 주제의 뒷부분에서 설명됩니다.

의도하지 않은 형식이 로드되지 않도록 방지

의도하지 않은 형식을 로드하면 형식이 악의적이거나 보안에 민감한 부작용이 있는지 여부에 관계없이 중대한 결과를 초래할 수 있습니다. 형식은 악용 가능한 보안 취약성을 포함하거나, 생성자 또는 클래스 생성자에서 보안에 민감한 작업을 수행하거나, 서비스 거부 공격을 용이하게 하는 메모리 공간이 크거나, 복구할 수 없는 예외를 throw할 수 있습니다. 형식에는 형식이 로드되는 즉시 그리고 인스턴스를 만들기 전에 실행되는 클래스 생성자가 있을 수 있습니다. 이러한 이유로 역직렬 변환기가 로드할 수 있는 형식 집합을 제어하는 것이 중요합니다.

DataContractSerializer가 느슨하게 결합된 방식으로 역직렬화됩니다. 들어오는 데이터에서 CLR(공용 언어 런타임) 형식 및 어셈블리 이름을 읽지 않습니다. 이 동작은 XmlSerializer의 동작과 유사하지만, NetDataContractSerializerBinaryFormatter, SoapFormatter의 동작과는 다릅니다. 느슨한 결합은 원격 공격자가 메시지에서 해당 형식의 이름을 지정하기만 하면 로드할 임의 형식을 나타낼 수 없으므로 어느 정도의 안전성이 도입됩니다.

DataContractSerializer 계약에 따라 현재 예상되는 형식을 항상 로드할 수 있습니다. 예를 들어, 데이터 계약에 Customer 유형의 데이터 멤버가 있는 경우, DataContractSerializer는 이 데이터 멤버를 역직렬화할 때 Customer 유형을 로드할 수 있습니다.

DataContractSerializer 또한 다형성을 지원합니다. 데이터 멤버를 로 Object선언할 수 있지만 들어오는 데이터에는 인스턴스가 Customer 포함될 수 있습니다. Customer 형식이 역직렬 변환기에 하나의 메커니즘을 통해 "알려진" 경우에만 가능합니다.

  • KnownTypeAttribute 형식에 적용된 특성입니다.

  • KnownTypeAttribute 형식 목록을 반환하는 메서드를 지정하는 특성입니다.

  • ServiceKnownTypeAttribute 특성.

  • KnownTypes 구성 섹션입니다.

  • 직렬 변환기를 DataContractSerializer 직접 사용하는 경우 생성 중에 명시적으로 전달된 알려진 형식 목록입니다.

이러한 각 메커니즘은 역직렬 변환기가 로드할 수 있는 다양한 형식을 도입함으로써 표면적을 늘립니다. 이러한 각 메커니즘을 제어하여 알려진 형식 목록에 악의적이거나 의도하지 않은 형식이 추가되지 않도록 합니다.

알려진 형식이 범위에 있으면 언제든지 로드할 수 있으며 계약에서 실제로 사용하는 것을 금지하더라도 형식의 인스턴스를 만들 수 있습니다. 예를 들어 위의 메커니즘 중 하나를 사용하여 "MyDangerousType" 형식을 알려진 형식 목록에 추가한다고 가정합니다. 이는 다음을 의미합니다.

  • MyDangerousType 가 로드되고 해당 클래스 생성자가 실행됩니다.

  • 문자열 데이터 멤버를 사용하여 데이터 계약을 역직렬화하는 경우에도 악의적인 메시지로 인해 인스턴스 MyDangerousType 가 생성될 수 있습니다. MyDangerousType 속성 setter와 같은 코드가 실행될 수 있습니다. 이 작업이 완료되면 역직렬 변환기가 문자열 데이터 멤버에 이 인스턴스를 할당하려고 시도하고 예외로 실패합니다.

알려진 형식 목록을 반환하는 메서드를 작성하거나 목록을 생성자에 직접 DataContractSerializer 전달할 때 목록을 준비하는 코드가 안전하고 신뢰할 수 있는 데이터에서만 작동하는지 확인합니다.

구성에서 알려진 형식을 지정하는 경우 구성 파일이 안전한지 확인합니다. 형식이 있는 서명된 어셈블리의 공개 키를 지정하여 구성에서 항상 강력한 이름을 사용하지만 로드할 형식의 버전을 지정하지는 않습니다. 가능한 경우 형식 로더가 자동으로 최신 버전을 선택합니다. 구성에서 특정 버전을 지정하는 경우 다음 위험을 실행합니다. 형식에 향후 버전에서 수정될 수 있는 보안 취약성이 있을 수 있지만 구성에서 명시적으로 지정되었으므로 취약한 버전이 계속 로드됩니다.

알려진 형식이 너무 많을 때에는 또 다른 결과가 있습니다. 즉, DataContractSerializer가 애플리케이션 도메인에 직렬화/역직렬화 코드 캐시를 생성하며, 각 형식에 대한 항목을 직렬화하고 역직렬화해야 하기 때문입니다. 애플리케이션 도메인이 실행되는 한 이 캐시는 지워지지 않습니다. 따라서 애플리케이션이 많은 알려진 형식을 사용한다는 것을 알고 있는 공격자는 이러한 모든 형식의 역직렬화를 유발하여 캐시가 불균형적으로 많은 양의 메모리를 소비하게 할 수 있습니다.

의도하지 않은 상태에 타입이 들어가는 것을 방지

형식에는 적용해야 하는 내부 일관성 제약 조건이 있을 수 있습니다. 역직렬화 중에 이러한 제약 조건을 위반하지 않도록 주의해야 합니다.

다음 유형의 예제는 우주선의 에어록 상태를 나타내며 내부 문과 외부 문을 동시에 열 수 없다는 제약 조건을 적용합니다.

[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

공격자는 이와 같은 악의적인 메시지를 보내 제약 조건을 해결한 후 개체를 잘못된 상태로 전환하여 의도하지 않고 예측할 수 없는 결과를 초래할 수 있습니다.

<SpaceStationAirlock>
    <innerDoorOpen>true</innerDoorOpen>
    <outerDoorOpen>true</outerDoorOpen>
</SpaceStationAirlock>

이 상황은 다음 사항을 인식하여 방지할 수 있습니다.

  • 대부분의 클래스를 DataContractSerializer 역직렬화하면 생성자가 실행되지 않습니다. 따라서 생성자에서 수행된 상태 관리에 의존하지 마세요.

  • 콜백을 사용하여 개체가 유효한 상태인지 확인합니다. 특성으로 OnDeserializedAttribute 표시된 콜백은 역직렬화가 완료된 후 실행되고 전체 상태를 검사하고 수정할 수 있기 때문에 특히 유용합니다. 자세한 내용은 Version-Tolerant Serialization 콜백을 참조하세요.

  • 속성 setter를 호출해야 하는 특정 순서에 의존하도록 데이터 계약 형식을 디자인하지 마세요.

  • 특성으로 표시된 레거시 형식을 사용하여 주의하세요 SerializableAttribute . 이들 중 상당수는 신뢰할 수 있는 데이터에서만 사용할 수 있도록 .NET Framework 원격 작업을 사용하도록 설계되었습니다. 이 특성으로 표시된 기존 형식은 상태 안전을 염두에 두고 설계되지 않았을 수 있습니다.

  • IsRequired 속성의 DataMemberAttribute 특성에 의존하여 데이터의 존재를 상태 안전에 관해 보장하지 마십시오. 데이터는 항상 null, zero, 또는 invalid일 수 있습니다.

  • 먼저 유효성을 검사하지 않고 신뢰할 수 없는 데이터 원본에서 역직렬화된 개체 그래프를 신뢰하지 마세요. 각 개별 개체는 일관된 상태일 수 있지만 개체 그래프 전체가 아닐 수 있습니다. 또한 개체 그래프 보존 모드를 사용하지 않도록 설정하더라도 역직렬화된 그래프에는 동일한 개체에 대한 여러 참조가 있거나 순환 참조가 있을 수 있습니다. 자세한 내용은 직렬화 및 역직렬화를 참조하세요.

NetDataContractSerializer를 안전하게 사용

NetDataContractSerializer는 유형에 강한 결합을 사용하는 시리얼라이제이션 엔진입니다. 이는 BinaryFormatterSoapFormatter와 비슷합니다. 즉, 들어오는 데이터에서 .NET Framework 어셈블리 및 형식 이름을 읽어 인스턴스화할 형식을 결정합니다. WCF의 일부이지만 이 serialization 엔진에는 제공된 연결 방법이 없습니다. 사용자 지정 코드를 작성해야 합니다. NetDataContractSerializer는 주로 .NET Framework 원격에서 WCF로의 마이그레이션을 용이하게 하기 위해 제공됩니다. 자세한 내용은 Serialization 및 Deserialization의 관련 섹션을 참조하세요.

메시지 자체는 모든 형식을 로드 NetDataContractSerializer 할 수 있음을 나타낼 수 있으므로 메커니즘은 본질적으로 안전하지 않으며 신뢰할 수 있는 데이터에서만 사용해야 합니다. 자세한 내용은 BinaryFormatter 보안 가이드를 참조하세요.

신뢰할 수 있는 데이터와 함께 사용하더라도, 들어오는 데이터가 로드할 형식을 충분히 지정하지 않을 수 있습니다. 특히 속성이 AssemblyFormat로 설정된 Simple 경우입니다. 애플리케이션의 디렉터리 또는 전역 어셈블리 캐시에 액세스할 수 있는 모든 사용자는 로드해야 하는 형식 대신 악의적인 형식을 대체할 수 있습니다. 사용 권한을 올바르게 설정하여 항상 애플리케이션 디렉터리와 전역 어셈블리 캐시의 보안을 보장합니다.

일반적으로, NetDataContractSerializer 인스턴스에 부분적으로 신뢰할 수 있는 코드의 액세스를 허용하거나 서로게이트 선택기(ISurrogateSelector) 또는 직렬화 바인더(SerializationBinder)를 제어하는 경우, 해당 코드는 직렬화/역직렬화 과정에 대해 많은 제어권을 행사할 수 있습니다. 예를 들어 임의 형식을 삽입하거나, 정보를 공개하거나, 결과 개체 그래프 또는 serialize된 데이터를 조작하거나, 결과 serialize된 스트림을 오버플로할 수 있습니다.

또 다른 보안 문제는 NetDataContractSerializer 악의적인 코드 실행 위협이 아니라 서비스 거부입니다. 이 NetDataContractSerializer값을 사용하는 경우 항상 할당량을 MaxItemsInObjectGraph 안전한 값으로 설정합니다. 크기가 이 할당량에 의해서만 제한된 개체 배열을 할당하는 작은 악성 메시지를 쉽게 생성할 수 있습니다.

XmlSerializer-Specific 위협

XmlSerializer 보안 모델은 .의 보안 모델과 DataContractSerializer비슷합니다. XmlSerializer에 고유한 몇 가지 위협이 있습니다.

XmlSerializer 실제로 직렬화 및 역직렬화하는 코드를 포함하는 serialization 어셈블리를 런타임에 생성합니다. 이러한 어셈블리는 임시 파일 디렉터리에 만들어집니다. 일부 다른 프로세스 또는 사용자에게 해당 디렉터리에 대한 액세스 권한이 있는 경우 임의 코드로 serialization/deserialization 코드를 덮어쓸 수 있습니다. 그러면 XmlSerializer는 serialization/deserialization 코드를 대신해 보안 컨텍스트에서 이 코드를 실행합니다. 이러한 일이 발생하지 않도록 임시 파일 디렉터리에 대한 사용 권한이 올바르게 설정되어 있는지 확인합니다.

XmlSerializer 또한 런타임에 생성하지 않고 미리 생성된 serialization 어셈블리를 사용하는 모드도 있습니다. 이 모드는 적절한 직렬화 어셈블리를 XmlSerializer이(가) 찾을 수 있을 때마다 활성화됩니다. XmlSerializer는 직렬화 어셈블리가 직렬화되는 형식을 포함하는 어셈블리를 서명하는 데 사용된 것과 동일한 키로 서명되었는지 여부를 확인합니다. 이를 통해 serialization 어셈블리로 위장되는 악의적인 어셈블리로부터 보호할 수 있습니다. 그러나 직렬화 가능한 형식이 포함된 어셈블리가 서명되지 않은 경우, XmlSerializer는 이 검사를 수행할 수 없으며 올바른 이름의 어셈블리를 사용합니다. 이렇게 하면 악성 코드를 실행할 수 있습니다. 항상 직렬화 가능한 형식이 포함된 어셈블리에 서명하거나 애플리케이션의 디렉터리 및 전역 어셈블리 캐시에 대한 액세스를 엄격하게 제어하여 악의적인 어셈블리가 도입되지 않도록 합니다.

서비스 XmlSerializer 거부 공격의 대상이 될 수 있습니다. XmlSerializer에는 MaxItemsInObjectGraph 할당량이 없으며, DataContractSerializer에는 할당량이 있습니다. 따라서 메시지 크기로만 제한되는 임의의 개체 양을 역직렬화합니다.

부분 신뢰 위협

부분 신뢰로 실행되는 코드와 관련된 위협과 관련된 다음과 같은 문제에 유의하세요. 이러한 위협에는 악의적인 부분적으로 신뢰할 수 있는 코드와 다른 공격 시나리오와 함께 부분적으로 신뢰할 수 있는 악의적인 코드가 포함됩니다(예: 특정 문자열을 구성한 다음 역직렬화하는 부분적으로 신뢰할 수 있는 코드).

  • serialization 구성 요소를 사용할 때는, 모든 serialization 시나리오가 어설션 범위 내에 있더라도, 그리고 신뢰할 수 없는 데이터 또는 객체를 다루지 않더라도 이러한 사용 전에 권한을 주장하지 마세요. 이러한 사용은 보안 취약성으로 이어질 수 있습니다.

  • 부분적으로 신뢰할 수 있는 코드가 확장성 지점(서로게이트), 직렬화되는 형식 또는 다른 수단을 통해 직렬화 프로세스를 제어할 수 있는 경우 부분적으로 신뢰할 수 있는 코드로 인해 serialize된 스트림에 대량의 데이터가 출력되어 DoS(서비스 거부)가 이 스트림의 수신기로 발생할 수 있습니다. DoS 위협에 민감한 대상에 대한 데이터를 직렬화할 때, 부분적으로 신뢰할 수 있는 형식을 직렬화하거나 부분적으로 신뢰할 수 있는 코드가 직렬화를 제어하지 않도록 하세요.

  • DataContractSerializer 인스턴스에 부분적으로 신뢰할 수 있는 코드에 대한 액세스를 허용하거나 데이터 계약 서로게이트를 제어하는 경우, 해당 프로세스의 직렬화/역직렬화에 대해 많은 제어 권한을 가질 수 있습니다. 예를 들어 임의 형식을 삽입하거나, 정보를 공개하거나, 결과 개체 그래프 또는 serialize된 데이터를 조작하거나, 결과 serialize된 스트림을 오버플로할 수 있습니다. 동일한 NetDataContractSerializer 위협은 "NetDataContractSerializer를 안전하게 사용" 섹션에 설명되어 있습니다.

  • DataContractAttribute 특성이 형식에 적용되거나 형식이 SerializableAttribute로 표시되었지만 ISerializable가 아닌 경우, 역직렬화기는 모든 생성자가 비공개이거나 요구에 의해 보호된 경우에도 해당 형식의 인스턴스를 생성할 수 있습니다.

  • 역직렬화할 데이터를 신뢰할 수 있고 알려진 모든 형식이 신뢰할 수 있는 형식이라고 확신하지 않는 한 역직렬화 결과를 신뢰하지 마세요. 부분 신뢰에서 실행할 때 알려진 형식은 애플리케이션 구성 파일에서 로드되지 않지만 컴퓨터 구성 파일에서 로드됩니다.

  • 부분적으로 신뢰할 수 있는 DataContractSerializer 코드에 추가된 서로게이트가 있는 인스턴스를 전달하는 경우 코드는 해당 서로게이트에서 수정 가능한 설정을 변경할 수 있습니다.

  • 역직렬화된 개체의 경우 XML 판독기(또는 그 안에 있는 데이터)가 부분적으로 신뢰할 수 있는 코드에서 가져온 경우 결과 역직렬화된 개체를 신뢰할 수 없는 데이터로 처리합니다.

  • 형식에 ExtensionDataObject 공용 멤버가 없다는 사실은 형식 내의 데이터가 안전하다는 것을 의미하지는 않습니다. 예를 들어 권한 있는 데이터 원본에서 일부 데이터가 있는 개체로 역직렬화한 다음 해당 개체를 부분적으로 신뢰할 수 있는 코드에 전달하는 경우 부분적으로 신뢰할 수 있는 코드는 ExtensionDataObject 개체를 직렬화하여 데이터를 읽을 수 있습니다. 역직렬화하는 경우, IgnoreExtensionDataObject를 설정하는 것이 좋습니다. 권한 있는 데이터 출처에서 가져온 객체가 나중에 부분적으로 신뢰할 수 있는 코드로 전달될 때입니다.

  • DataContractSerializerDataContractJsonSerializer는 완전 신뢰 하에서 프라이빗, 보호, 내부 및 공용 멤버의 직렬화를 지원합니다. 그러나 부분 신뢰에서는 공용 멤버만 직렬화할 수 있습니다. 애플리케이션이 비공용 멤버를 직렬화하려고 하면 SecurityException이 발생합니다.

    내부 또는 보호된 내부 멤버를 부분 신뢰로 직렬화할 수 있도록 하려면 어셈블리 특성을 사용합니다 InternalsVisibleToAttribute . 이 특성을 사용하면 어셈블리가 내부 멤버가 다른 어셈블리에 표시되도록 선언할 수 있습니다. 이러한 경우, 내부 멤버를 직렬화하려는 어셈블리는 내부 멤버가 System.Runtime.Serialization.dll에 노출되도록 설정합니다.

    이 방법의 장점은 상승된 코드 생성 경로가 필요하지 않다는 것입니다.

    동시에 두 가지 주요 단점이 있습니다.

    첫 번째 단점은 InternalsVisibleToAttribute 속성의 선택적 속성이 어셈블리 전반에 걸쳐 적용된다는 점입니다. 즉, 특정 클래스만 내부 멤버를 직렬화할 수 있도록 지정할 수 없습니다. 물론 해당 멤버에 특성을 추가 DataMemberAttribute 하지 않고 특정 내부 멤버를 직렬화하지 않도록 선택할 수 있습니다. 마찬가지로 개발자는 약간의 가시성 문제가 있는 비공개 또는 보호된 멤버가 아닌 내부 멤버를 만들도록 선택할 수도 있습니다.

    두 번째 단점은 여전히 개인 또는 보호된 멤버를 지원하지 않는다는 것입니다.

    부분 신뢰에서 InternalsVisibleToAttribute 속성을 사용하는 방법을 설명하기 위해, 다음 프로그램을 고려해 보세요.

        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";
            }
        }
    

    위의 PermissionsHelper.InternetZone 예제에서 부분 신뢰에 PermissionSet 해당합니다. 이제 InternalsVisibleToAttribute 특성이 없으면 애플리케이션이 실패하고, SecurityException 예외를 발생시켜 비공용 멤버를 부분 신뢰에서 직렬화할 수 없음을 나타냅니다.

    그러나 원본 파일에 다음 줄을 추가하면 프로그램이 성공적으로 실행됩니다.

    [assembly:System.Runtime.CompilerServices.InternalsVisibleTo("System.Runtime.Serialization, PublicKey = 00000000000000000400000000000000")]
    

기타 상태 관리 문제

개체 상태 관리와 관련된 몇 가지 다른 문제는 다음과 같습니다.

  • 스트리밍 전송과 함께 스트림 기반 프로그래밍 모델을 사용하는 경우 메시지가 도착하면 메시지 처리가 발생합니다. 메시지의 발신자가 스트림 중간에 보내기 작업을 중단하여 더 많은 콘텐츠가 필요한 경우 코드를 예측할 수 없는 상태로 남을 수 있습니다. 일반적으로 완료되는 스트림에 의존하지 않으며 스트림이 중단된 경우 롤백할 수 없는 스트림 기반 작업에서는 작업을 수행하지 않습니다. 이는 스트리밍 본문 다음에 메시지가 잘못된 형식이 될 수 있는 상황에도 적용됩니다(예: SOAP 봉투에 대한 끝 태그가 누락되거나 두 번째 메시지 본문이 있을 수 있음).

  • IExtensibleDataObject 기능을 사용하면 중요한 데이터가 내보내질 수 있습니다. 신뢰할 수 없는 원본의 데이터를 데이터 계약으로 IExtensibleObjectData 수락하고 나중에 메시지가 서명된 보안 채널에서 다시 내보내는 경우, 알 수 없는 데이터를 보증할 수 있습니다. 또한 알려진 데이터와 알 수 없는 데이터를 모두 고려하면 보내는 전체 상태가 유효하지 않을 수 있습니다. 확장 데이터 속성을 null 선택적으로 설정하거나 선택적으로 기능을 사용하지 않도록 설정하여 이 상황을 방지합니다 IExtensibleObjectData .

스키마 가져오기

일반적으로 형식을 생성하기 위해 스키마를 가져오는 프로세스는 디자인 타임(예: 웹 서비스에서 ServiceModel 메타데이터 유틸리티 도구(Svcutil.exe) 을 사용하여 클라이언트 클래스를 생성하는 경우에만 발생합니다. 그러나 고급 시나리오에서는 런타임에 스키마를 처리할 수 있습니다. 이렇게 하면 서비스 거부 위험에 노출될 수 있습니다. 일부 스키마를 가져오는 데 시간이 오래 걸릴 수 있습니다. 스키마가 XmlSerializer 신뢰할 수 없는 원본에서 제공될 수 있는 경우 이러한 시나리오에서 스키마 가져오기 구성 요소를 사용하지 마세요.

ASP.NET AJAX 통합과 관련된 위협

사용자가 WebScriptEnablingBehavior 또는 WebHttpBehavior를 구현하면, WCF는 XML 및 JSON 메시지를 모두 수락할 수 있는 엔드포인트를 제공합니다. 그러나 XML 판독기와 JSON 판독기 모두에서 사용되는 판독기 할당량 집합은 하나뿐입니다. 일부 할당량 설정은 한 명에게 적합하지만 다른 사람에게는 너무 클 수 있습니다.

구현할 WebScriptEnablingBehavior때 사용자에게는 엔드포인트에서 JavaScript 프록시를 노출하는 옵션이 있습니다. 다음 보안 문제를 고려해야 합니다.

  • JavaScript 프록시를 검사하여 서비스에 대한 정보(작업 이름, 매개 변수 이름 등)를 가져올 수 있습니다.

  • JavaScript 엔드포인트를 사용하는 경우 중요한 개인 정보가 클라이언트 웹 브라우저 캐시에 보존될 수 있습니다.

구성 요소에 대한 참고 사항

WCF는 유연하고 사용자 지정 가능한 시스템입니다. 이 항목의 내용 대부분은 가장 일반적인 WCF 사용 시나리오에 중점을 줍니다. 그러나 WCF에서 제공하는 구성 요소는 여러 가지 방법으로 작성할 수 있습니다. 각 구성 요소를 사용할 때 보안에 미치는 영향을 이해하는 것이 중요합니다. 특히 다음 사항에 주의하십시오.

  • XML 판독기를 사용해야 하는 경우 다른 판독기 대신 클래스에서 XmlDictionaryReader 제공하는 판독기를 사용합니다. 안전한 판독기는 CreateTextReader, CreateBinaryReader, 또는 CreateMtomReader 메서드를 사용하여 생성됩니다. 메서드를 Create 사용하지 마세요. 항상 안전한 할당량으로 판독기를 구성합니다. WCF의 serialization 엔진은 WCF의 보안 XML 판독기에서 사용하는 경우에만 안전합니다.

  • 신뢰할 수 없는 데이터를 DataContractSerializer로 역직렬화하는 경우, 항상 MaxItemsInObjectGraph 속성을 설정합니다.

  • 메시지를 만들 때 충분한 보호를 제공하지 않는 경우 maxSizeOfHeaders 매개 변수를 설정합니다MaxReceivedMessageSize.

  • 인코더를 만들 때는 항상 관련 할당량(예: MaxSessionSizeMaxBufferSize)을 구성합니다.

  • XPath 메시지 필터를 사용하는 경우 필터가 NodeQuota 방문하는 XML 노드의 양을 제한하도록 설정합니다. 많은 노드를 방문하지 않고 계산하는 데 시간이 오래 걸릴 수 있는 XPath 식을 사용하지 마세요.

  • 일반적으로 할당량을 허용하는 구성 요소를 사용하는 경우 해당 보안 의미를 이해하고 안전한 값으로 설정합니다.

참고하십시오