Вопросы безопасности для данныхSecurity Considerations for Data

При работе с данными в Windows Communication Foundation (WCF) необходимо учитывать ряд категорий угроз.When dealing with data in Windows Communication Foundation (WCF), you must consider a number of threat categories. В следующем списке показаны наиболее важные классы угроз, связанные с обработкой данных.The following list shows the most important threat classes that relate to data processing. WCF предоставляет средства для устранения этих угроз.WCF provides tools to mitigate these threats.

  • отказ в обслуживании;Denial of service

    При получении ненадежных данных они могут заставить получающую сторону задействовать неограниченное количество различных ресурсов, например памяти, потоков, доступных подключений или количества тактов процессора, что приведет к продолжительным расчетам.When receiving untrusted data, the data may cause the receiving side to access a disproportionate amount of various resources, such as memory, threads, available connections, or processor cycles by causing lengthy computations. Атака типа "отказ в обслуживании" в отношении сервера может стать причиной его сбоя и невозможности обработки сообщений от других, допустимых клиентов.A denial-of-service attack against a server may cause it to crash and be unable to process messages from other, legitimate clients.

  • Выполнение вредоносного кодаMalicious code execution

    Входящие ненадежные данные заставляют получающую сторону выполнить код сторонний код.Incoming untrusted data causes the receiving side to run code it did not intend to.

  • раскрытие информации;Information disclosure

    Удаленный злоумышленник заставляет получающую сторону отвечать на его запросы таким образом, чтобы раскрыть больше информации, чем необходимо.The remote attacker forces the receiving party to respond to its requests in such a way as to disclose more information than it intends to.

Предоставляемый пользователем код и управление доступом для кодаUser-Provided Code and Code Access Security

Несколько мест в инфраструктуре Windows Communication Foundation (WCF) выполняют код, предоставленный пользователем.A number of places in the Windows Communication Foundation (WCF) infrastructure run code that is provided by the user. Например, ядро сериализации DataContractSerializer может вызывать предоставляемые пользователем методы доступа к свойству set и get .For example, the DataContractSerializer serialization engine may call user-provided property set accessors and get accessors. Инфраструктура WCF Channel также может вызывать предоставляемые пользователем производные классы Message класса.The WCF channel infrastructure may also call into user-provided derived classes of the Message class.

Автор кода должен обеспечить отсутствие слабых мест в системе безопасности.It is the responsibility of the code author to ensure that no security vulnerabilities exist. Например, при создании типа контракта данных со свойством элемента данных целочисленного типа и при выделении памяти для массива, основанного на значении свойства, в реализации метода доступа set , вполне вероятна атака типа "отказ в обслуживании", если во вредоносном сообщении содержится крайне большое значение для этого элемента данных.For example, if you create a data contract type with a data member property of type integer, and in the set accessor implementation allocate an array based on the property value, you expose the possibility of a denial-of-service attack if a malicious message contains an extremely large value for this data member. В целом следует избегать любого выделения памяти, основанного на входящих данных, или продолжительной обработки в предоставленном пользователем коде (в особенности если причиной продолжительной обработки является небольшой объем входящих данных).In general, avoid any allocations based on incoming data or lengthy processing in user-provided code (especially if lengthy processing can be caused by a small amount of incoming data). При выполнении анализа безопасности предоставленного пользователем кода следует также изучить все случаи сбоев (т.е. все ветви кода, в которых вызываются исключения).When performing security analysis of user-provided code, make sure to also consider all failure cases (that is, all code branches where exceptions are thrown).

Простым примером кода, предоставленного пользователем, может служить код в реализации службы для каждой операции.The ultimate example of user-provided code is the code inside your service implementation for each operation. За безопасность реализации службы отвечает разработчик.The security of your service implementation is your responsibility. Существует вероятность случайного создания небезопасных реализаций операций, которые могут стать причиной уязвимости для атак типа "отказ в обслуживании".It is easy to inadvertently create insecure operation implementations that may result in denial-of-service vulnerabilities. Например операция, которая принимает строку и возвращает из базы данных список клиентов, чьи имена начинаются с этой строки.For example, an operation that takes a string and returns the list of customers from a database whose name starts with that string. Если осуществляется работа с большими базами данных и передаваемая строка представляет собой всего лишь одну букву, код может попытаться создать сообщение, чей размер больше размера всей доступной памяти, что приведет к сбою всей службы.If you are working with a large database and the string being passed is just a single letter, your code may attempt to create a message larger than all available memory, causing the entire service to fail. (Элемент OutOfMemoryException не может быть восстановлен в .NET Framework и всегда приводит к завершению работы приложения.)(An OutOfMemoryException is not recoverable in the .NET Framework and always results in the termination of your application.)

Следует гарантировать, что вредоносный код не попадет в систему в разных точках расширяемости.You should ensure that no malicious code is plugged in to the various extensibility points. Это особенно уместно в случае частичного доверия, когда ведется работа с частично доверенными сборками или создаются компоненты, используемые частично доверенным кодом.This is especially relevant when running under partial trust, dealing with types from partially-trusted assemblies, or creating components usable by partially-trusted code. Дополнительные сведения см. далее в разделе "Угрозы частично доверенных компонентов".For more information, see "Partial Trust Threats" in a later section.

Обратите внимание, что при частичном доверии инфраструктура сериализации контракта данных поддерживает только ограниченный набор модели программирования контрактов данных (например элементы закрытых данных или типы, использующие атрибуты SerializableAttribute , не поддерживаются).Note that when running in partial trust, the data contract serialization infrastructure supports only a limited subset of the data contract programming model - for example, private data members or types using the SerializableAttribute attribute are not supported. Дополнительные сведения см. в разделе частичное доверие.For more information, see Partial Trust.

Предупреждение ненамеренного раскрытия информацииAvoiding Unintentional Information Disclosure

При разработке сериализуемых типов с учетом безопасности следует обратить внимание на проблему раскрытия информации.When designing serializable types with security in mind, information disclosure is a possible concern.

Учтите следующие моменты.Consider the following points:

  • Модель программирования DataContractSerializer допускает раскрытие во время сериализации закрытых и внутренних данных за пределы типа или сборки.The DataContractSerializer programming model allows the exposure of private and internal data outside of the type or assembly during serialization. Кроме того, во время экспорта схемы возможно раскрытие формы типа.Additionally, the shape of a type can be exposed during schema export. Важно понимать проекцию сериализации типа.Be sure to understand your type's serialization projection. Чтобы предотвратить раскрытие любой информации, необходимо отключить сериализацию (например не применяя атрибут DataMemberAttribute в случае контракта данных).If you do not want anything exposed, disable serializing it (for example, by not applying the DataMemberAttribute attribute in the case of a data contract).

  • Помните, что один и тот же тип может иметь несколько проекций сериализации в зависимости от используемого сериализатора.Be aware that the same type may have multiple serialization projections, depending on the serializer in use. Один и тот же тип может раскрывать один набор данных при использовании с DataContractSerializer и другой - при использовании с XmlSerializer.The same type may expose one set of data when used with the DataContractSerializer and another set of data when used with the XmlSerializer. Случайное использование неправильного сериализатора может стать причиной раскрытия информации.Accidentally using the wrong serializer may lead to information disclosure.

  • Использование XmlSerializer в режиме вызова устаревших удаленных процедур (RPC)/encoded может случайно раскрыть форму графа объекта на отправляющей стороне в отношении получающей стороны.Using the XmlSerializer in legacy remote procedure call (RPC)/encoded mode may unintentionally expose the shape of the object graph on the sending side to the receiving side.

Предотвращение атак типа "отказ в обслуживании"Preventing Denial-of-Service Attacks

КвотыQuotas

Если получающая сторона выделяет значительный объем памяти, это потенциальная атака типа "отказ в обслуживании".Causing the receiving side to allocate a significant amount of memory is a potential denial-of-service attack. Несмотря на то что в этом разделе особое внимание уделяется проблемам потребления памяти, возникающим в случае больших сообщений, также могут возникать и другие атаки.While this section concentrates on memory consumption issues arising from large messages, other attacks may occur. Например, сообщения могут требовать неограниченного времени на обработку.For example, messages may use a disproportionate amount of processing time.

Атаки типа "отказ в обслуживании" обычно предотвращаются путем использования квот.Denial-of-service attacks are usually mitigated using quotas. При превышении квоты, как правило, выдается исключение QuotaExceededException .When a quota is exceeded, a QuotaExceededException exception is normally thrown. Без использования квот вредоносное сообщение может задействовать всю доступную память (что приведет к исключению OutOfMemoryException ) или все доступные стеки (как следствие - исключение StackOverflowException).Without the quota, a malicious message may cause all available memory to be accessed, resulting in an OutOfMemoryException exception, or all available stacks to be accessed, resulting in a StackOverflowException.

В сценарии превышенных квот предусмотрено устранение ошибок. При возникновении ошибки в работающей службе, обрабатываемое в настоящий момент сообщение удаляется, и служба продолжает работать и обрабатывать последующие сообщения.The quota exceeded scenario is recoverable; if encountered in a running service, the message currently being processed is discarded and the service keeps running and processes further messages. Однако сценарии нехватки памяти и переполнения стека не могут быть восстановлены в любом месте .NET Framework; служба завершает работу, если она сталкивается с такими исключениями.The out-of-memory and stack overflow scenarios, however, are not recoverable anywhere in the .NET Framework; the service terminates if it encounters such exceptions.

Квоты в WCF не требуют предварительного выделения.Quotas in WCF do not involve any pre-allocation. Например, если квота MaxReceivedMessageSize (в различных классах) задана как 128 КБ, это не означает, что для каждого сообщения автоматически выделяется 128 КБ.For example, if the MaxReceivedMessageSize quota (found on various classes) is set to 128 KB, it does not mean that 128 KB is automatically allocated for each message. Выделяемый объем зависит от фактического размера входящего сообщения.The actual amount allocated depends on the actual incoming message size.

На транспортном уровне предусмотрено большое количество квот.Many quotas are available at the transport layer. Эти квоты принудительно применяются в соответствии с используемым специальным каналом транспорта (HTTP, TCP и т. д.).These are quotas enforced by the specific transport channel in use (HTTP, TCP, and so on). В этом разделе представлено описание только некоторых из этих квот, подробную информацию по квотам см. в разделе Transport Quotas.While this topic discusses some of these quotas, these quotas are described in detail in Transport Quotas.

Уязвимость, связанная с использованием хэш-таблицHashtable Vulnerability

Если контракты данных содержат хэш-таблицы или коллекции, возникает потенциальная уязвимость.A vulnerability exists when data contracts contain hashtables or collections. Проблема обнаруживается при вставке большого количества значений в хэш-таблицу, если для значительной части этих значений создается одно и то же значение хэша.The problem occurs if a large number of values are inserted into a hashtable where a large number of those values generate the same hash value. Это можно использовать для DOS-атаки.This can be used as a DOS attack. Эту уязвимость можно устранить, установив квоту привязки MaxReceivedMessageSize.This vulnerability can be mitigated by setting the MaxReceivedMessageSize binding quota. Следует задавать эту квоту с осторожностью, чтобы предотвратить атаки.Care must be taken while setting this quota in order to prevent such attacks. Эта квота устанавливает верхний предел на размер сообщения WCF.This quota puts an upper limit on the size of WCF message. Кроме того, избегайте использования хэш-таблиц или коллекций в контрактах данных.Additionally, avoid using hashtables or collections in your data contracts.

Ограничение потребления памяти без потоковой передачиLimiting Memory Consumption Without Streaming

Модель безопасности в отношении больших сообщений зависит от того, используется ли потоковая передача.The security model around large messages depends on whether streaming is in use. В основном, в непотоковом случае сообщения буферизуются в память.In the basic, non-streamed case, messages are buffered into memory. В этом случае следует использовать квоту MaxReceivedMessageSize в TransportBindingElement или в предоставленных системой привязках, чтобы обеспечить защиту от больших сообщений, ограничив максимальный размер сообщения, для которого выделяется память.In this case, use the MaxReceivedMessageSize quota on the TransportBindingElement or on the system-provided bindings to protect against large messages by limiting the maximum message size to access. Обратите внимание, что служба может обрабатывать несколько сообщений одновременно, в таком случае все они находятся в памяти.Note that a service may be processing multiple messages at the same time, in which case they are all in memory. Чтобы устранить эту угрозу, необходимо воспользоваться функцией регулирования.Use the throttling feature to mitigate this threat.

Также учтите, что MaxReceivedMessageSize не задает верхнюю границу на выделение памяти для каждого сообщения, а ограничивает размер памяти постоянным значением.Also note that MaxReceivedMessageSize does not place an upper bound on per-message memory consumption, but limits it to within a constant factor. Например, если MaxReceivedMessageSize равно 1 МБ, и получено и затем десериализовано сообщение размером 1 МБ, для хранения десериализованного графа объекта требуется больший объем памяти, что приводит к общему потреблению памяти больше 1 МБ.For example, if the MaxReceivedMessageSize is 1 MB and a 1-MB message is received and then deserialized, additional memory is required to contain the deserialized object graph, resulting in total memory consumption well over 1 MB. По этой причине следует избегать создания сериализуемых типов, которые могут стать причиной значительного потребления памяти при небольшом объеме входящих данных.For this reason, avoid creating serializable types that could result in significant memory consumption without much incoming data. Например, контракт данных "Миконтракт" с 50 необязательными полями элементов данных и дополнительными закрытыми полями 100 можно создать с помощью конструкции XML " <MyContract/> ".For example, a data contract "MyContract" with 50 optional data member fields and an additional 100 private fields could be instantiated with the XML construction "<MyContract/>". Такой XML выделяет память для 150 полей.This XML results in memory being accessed for 150 fields. Обратите внимание, что по умолчанию элементы данных необязательны.Note that data members are optional by default. Проблема усложняется, если такой тип является частью массива.The problem is compounded when such a type is part of an array.

Самого по себеMaxReceivedMessageSize недостаточно, чтобы избежать всех атак типа "отказ в обслуживании".MaxReceivedMessageSize alone is not enough to prevent all denial-of-service attacks. Например, десериализатор может принудительно десериализовывать граф объекта с глубоким вложением (объект, содержащий другой объект, который в свою очередь содержит еще один объект, и т. д.) посредством входящего сообщения.For example, the deserializer may be forced to deserialize a deeply-nested object graph (an object that contains another object that contains yet another one, and so on) by an incoming message. Чтобы десериализовать такие графы, DataContractSerializer и XmlSerializer вызывают методы вложенным образом.Both the DataContractSerializer and the XmlSerializer call methods in a nested way to deserialize such graphs. Глубокое вложение вызовов методов может стать причиной невозможности восстановления StackOverflowException.Deep nesting of method calls may result in an unrecoverable StackOverflowException. Эта угроза устраняется путем настройки квоты MaxDepth с целью ограничения уровня вложений XML, как описано в разделе "Безопасное использование XML" далее в этой теме.This threat is mitigated by setting the MaxDepth quota to limit the level of XML nesting, as discussed in the "Using XML Safely" section later in the topic.

Настройка дополнительных квот для MaxReceivedMessageSize особенно важна при использовании двоичного кодирования XML.Setting additional quotas to MaxReceivedMessageSize is especially important when using binary XML encoding. Использование двоичного кодирования в некотором смысле аналогично сжатию: небольшая группа байтов во входящем сообщении может представлять большой объем данных.Using binary encoding is somewhat equivalent to compression: a small group of bytes in the incoming message may represent a lot of data. Поэтому даже если сообщение соответствует ограничению MaxReceivedMessageSize , для полностью расширенной формы может потребоваться намного больший объем памяти.Thus, even a message fitting into the MaxReceivedMessageSize limit may take up much more memory in fully expanded form. Чтобы устранить такие угрозы, относящиеся к XML, следует правильно задать все квоты средства чтения XML, как описано в разделе "Безопасное использование XML" далее в этой теме.To mitigate such XML-specific threats, all of the XML reader quotas must be set correctly, as discussed in the "Using XML Safely" section later in this topic.

Ограничение потребления памяти с потоковой передачейLimiting Memory Consumption with Streaming

При потоковой передаче можно использовать небольшое значение MaxReceivedMessageSize , чтобы обеспечить защиту от атак типа "отказ в обслуживании".When streaming, you may use a small MaxReceivedMessageSize setting to protect against denial-of-service attacks. Однако потоковая передача допускает и более сложные сценарии.However, more complicated scenarios are possible with streaming. Например, служба отправки файлов принимает файлы, чей размер большей всей доступной памяти.For example, a file upload service accepts files larger than all available memory. В этом случае задайте для MaxReceivedMessageSize крайне высокое значение, предполагая, что в память не буферизуется практически никаких данных, и сообщение отправляет потоком непосредственно на диск.In this case, set the MaxReceivedMessageSize to an extremely large value, expecting that almost no data is buffered in memory and the message streams directly to disk. Если вредоносное сообщение может каким-либо образом принудительно заставить WCF буферизацию данных вместо потоковой передачи в этом случае, MaxReceivedMessageSize больше не защищает сообщение, обращающееся к доступной памяти.If a malicious message can somehow force WCF to buffer data instead of streaming it in this case, MaxReceivedMessageSize no longer protects against the message accessing all available memory.

Чтобы устранить эту угрозу, в различных компонентах обработки данных WCF существуют определенные параметры квоты, ограничивающие буферизацию.To mitigate this threat, specific quota settings exist on various WCF data-processing components that limit buffering. Наибольшее значение имеет свойство MaxBufferSize для различных элементов привязки транспорта и стандартных привязок.The most important of these is the MaxBufferSize property on various transport binding elements and standard bindings. При потоковой передаче эта квота должна быть задана с учетом максимального объема памяти, который следует выделить для каждого сообщения.When streaming, this quota should be set taking into account the maximum amount of memory you are willing to allocate per message. Как и в случае MaxReceivedMessageSizeпараметр не задает абсолютный максимальный объем потребляемой памяти, а только ограничивает его в пределах определенного диапазона.As with MaxReceivedMessageSize, the setting does not put an absolute maximum on memory consumption but only limits it to within a constant factor. Кроме того, как и в случае MaxReceivedMessageSizeпомните о возможности одновременной обработки нескольких сообщений.Also, as with MaxReceivedMessageSize, be aware of the possibility of multiple messages being processed simultaneously.

Подробные сведения о MaxBufferSizeMaxBufferSize Details

MaxBufferSizeСвойство ограничивает любую небольшую буферизацию WCF.The MaxBufferSize property limits any bulk buffering WCF does. Например, WCF всегда замещает заголовки SOAP и ошибки SOAP, а также любые части MIME, которые не находятся в естественном порядке чтения в сообщении о механизме оптимизации передачи сообщений (MTOM).For example, WCF always buffers SOAP headers and SOAP faults, as well as any MIME parts found to be not in the natural reading order in an Message Transmission Optimization Mechanism (MTOM) message. Этот параметр ограничивает объем буферизации во всех этих случаях.This setting limits the amount of buffering in all these cases.

WCF выполняет эту задачу, передавая MaxBufferSize значение различным компонентам, которые могут быть помещены в буфер.WCF accomplishes this by passing the MaxBufferSize value to the various components that may buffer. Например, некоторые перегрузки метода CreateMessage класса Message принимают параметр maxSizeOfHeaders .For example, some CreateMessage overloads of the Message class take a maxSizeOfHeaders parameter. WCF передает MaxBufferSize значение этому параметру, чтобы ограничить объем буферизации заголовков SOAP.WCF passes the MaxBufferSize value to this parameter to limit the amount of SOAP header buffering. Важно задать этот параметр при непосредственном использовании класса Message .It is important to set this parameter when using the Message class directly. Как правило, при использовании компонента в WCF, который принимает параметры квоты, важно понимать влияние этих параметров на безопасность и правильно задавать их.In general, when using a component in WCF that takes quota parameters, it is important to understand the security implications of these parameters and set them correctly.

Кодировщик сообщения MTOM также имеет параметр MaxBufferSize .The MTOM message encoder also has a MaxBufferSize setting. При использовании стандартных привязок он задается автоматически как значение на транспортном уровне MaxBufferSize .When using standard bindings, this is set automatically to the transport-level MaxBufferSize value. Однако при использовании элемента привязки кодировщика сообщения MTOM для создания пользовательской привязки важно задать свойство MaxBufferSize как безопасное значение в случае потоковой передачи.However, when using the MTOM message encoder binding element to construct a custom binding, it is important to set the MaxBufferSize property to a safe value when streaming is used.

Атаки при потоковой передаче, основанной на XMLXML-Based Streaming Attacks

MaxBufferSize не достаточно, чтобы обеспечить принудительную буферизацию WCF, когда ожидается потоковая передача.MaxBufferSize alone is not enough to ensure that WCF cannot be forced into buffering when streaming is expected. Например, средство чтения XML-кода WCF всегда замещает весь начальный тег XML-элемента во время начала чтения нового элемента.For example, the WCF XML readers always buffer the entire XML element start tag when starting to read a new element. Это осуществляется для правильной обработки пространств имен и атрибутов.This is done so that namespaces and attributes are properly processed. Если MaxReceivedMessageSize задан как большой (например, чтобы реализовать сценарий потоковой передачи большого диска непосредственно на диск), может быть создано вредоносное сообщение, в котором все тело сообщения представляет собой большой открывающий тег элемента XML.If MaxReceivedMessageSize is configured to be large (for example, to enable a direct-to-disk large file streaming scenario), a malicious message may be constructed where the entire message body is a large XML element start tag. Попытка чтения приводит к исключению OutOfMemoryException.An attempt to read it results in an OutOfMemoryException. Это одна из многих возможных атак типа «отказ в обслуживании» на основе XML, которые могут быть устранены с помощью квот модуля чтения XML, как описано в разделе «безопасное использование XML» далее в этом разделе.This is one of many possible XML-based denial-of-service attacks that can all be mitigated using XML reader quotas, discussed in the "Using XML Safely" section later in this topic. При потоковой передаче очень важно задать все такие квоты.When streaming, it is especially important to set all of these quotas.

Совместное использование моделей программирования потоковой передачи и буферизацииMixing Streaming and Buffering Programming Models

Причина многих потенциальных атак заключается в совместном использовании моделей программирования потоковой и непотоковой передачи в одной службе.Many possible attacks arise from mixing streaming and non-streaming programming models in the same service. Допустим, существует контракт службы с двумя операциями: одна принимает Stream , а другая - массив какого-либо пользовательского типа.Suppose there is a service contract with two operations: one takes a Stream and another takes an array of some custom type. Также предположим, что для MaxReceivedMessageSize задано большое значение, чтобы при первой операции обрабатывались большие потоки.Suppose also that MaxReceivedMessageSize is set to a large value to enable the first operation to process large streams. К сожалению, это означает, что большие сообщения могут быть отправлены и во вторую операцию, и десериализатор буферизует данные в память как массив до вызова операции.Unfortunately, this means that large messages can now be sent to the second operation as well, and the deserializer buffers data in memory as an array before the operation is called. Это потенциальная атака типа "отказ в обслуживании": квота MaxBufferSize не ограничивает размер тела сообщения, с которым работает десериализатор.This is a potential denial-of-service attack: the MaxBufferSize quota does not limit the size of the message body, which is what the deserializer works with.

По этой причине следует избегать совместного использования потоковых и непотоковых операций в одном и том же контракте.For this reason, avoid mixing stream-based and non-streamed operations in the same contract. В случае явной необходимости совместного использования обеих моделей программирования следует принять следующие меры предосторожности.If you absolutely must mix the two programming models, use the following precautions:

  • Выключите функцию IExtensibleDataObject , задав свойство IgnoreExtensionDataObjectServiceBehaviorAttribute как true.Turn off the IExtensibleDataObject feature by setting the IgnoreExtensionDataObject property of the ServiceBehaviorAttribute to true. Это обеспечит десериализацию только элементов, являющихся частью контракта.This ensures that only members that are a part of the contract are deserialized.

  • Задайте для свойства MaxItemsInObjectGraphDataContractSerializer безопасное значение.Set the MaxItemsInObjectGraph property of the DataContractSerializer to a safe value. Эта квота также доступна для атрибута ServiceBehaviorAttribute или через конфигурацию.This quota is also available on the ServiceBehaviorAttribute attribute or through configuration. Такая квота ограничивает число объектов, десериализуемых в одном эпизоде десериализации.This quota limits the number of objects that are deserialized in one deserialization episode. Как правило, каждый параметр операции или часть тела сообщения в контракте сообщения десериализуется в одном эпизоде.Normally, each operation parameter or message body part in a message contract is deserialized in one episode. При десериализации массивов каждая запись массива считается отдельным объектом.When deserializing arrays, each array entry is counted as a separate object.

  • Задайте для всех квот средства чтения XML безопасные значения.Set all of the XML reader quotas to safe values. Обратите внимание на MaxDepth, MaxStringContentLengthи MaxArrayLength и избегайте строк в непотоковых операциях.Pay attention to MaxDepth, MaxStringContentLength, and MaxArrayLength and avoid strings in non-streaming operations.

  • Просмотрите список известных типов, помня, что каждый из них можно создать в любой момент времени (см. раздел "Предотвращение загрузки непредусмотренных типов" далее в этой теме).Review the list of known types, keeping in mind that any one of them can be instantiated at any time (see the "Preventing Unintended Types from Being Loaded" section later in this topic).

  • Не используйте какие-либо типы, реализующие интерфейс IXmlSerializable , который буферизует большой объем данных.Do not use any types that implement the IXmlSerializable interface that buffer a lot of data. Не добавляйте такие типы в список известных типов.Do not add such types to the list of known types.

  • Не используйте массивы XmlElement, XmlNode , Byte или типы, реализующие ISerializable в контракте.Do not use the XmlElement, XmlNode arrays, Byte arrays, or types that implement ISerializable in a contract.

  • Не используйте массивы XmlElement, XmlNode , Byte или типы, реализующие ISerializable в списке известных типов.Do not use the XmlElement, XmlNode arrays, Byte arrays, or types that implement ISerializable in the list of known types.

Указанные выше меры предосторожности принимаются, когда непотоковая операция использует DataContractSerializer.The preceding precautions apply when the non-streamed operation uses the DataContractSerializer. Запрещается совместное использование потоковых и непотоковых моделей программирования в одной и той же службе, если используется XmlSerializer, поскольку для него не предусмотрена защита квотой MaxItemsInObjectGraph .Never mix streaming and non-streaming programming models on the same service if you are using the XmlSerializer, because it does not have the protection of the MaxItemsInObjectGraph quota.

Атаки типа "медленная потоковая передача"Slow Stream Attacks

Класс атак типа "отказ в обслуживании" при потоковой передаче не относится к потреблению памяти.A class of streaming denial-of-service attacks does not involve memory consumption. Вместо этого при такой атаке происходит замедление работы отправителя или получателя данных.Instead, the attack involves a slow sender or receiver of data. По мере ожидания отправки или получения данных истощаются такие ресурсы, как потоки и доступные подключения.While waiting for the data to be sent or received, resources such as threads and available connections are exhausted. Такая ситуация может возникнуть либо в результате вредоносной атаки, либо вследствие допустимого отправителя/получателя с медленным сетевым подключением.This situation could arise either as a result of a malicious attack or from a legitimate sender/receiver on a slow network connection.

Чтобы устранить такие атаки, следует правильно задать значения времени ожидания транспорта.To mitigate these attacks, set the transport time-outs correctly. Дополнительные сведения см. в разделе квоты транспорта.For more information, see Transport Quotas. Во вторых, никогда не используйте синхронные Read Write операции OR при работе с потоками в WCF.Secondly, never use synchronous Read or Write operations when working with streams in WCF.

Безопасное использование XMLUsing XML Safely

Примечание

Несмотря на то что этот раздел посвящен XML, информация также относится к документам JavaScript Object Notation (JSON).Although this section is about XML, the information also applies to JavaScript Object Notation (JSON) documents. При использовании Mapping Between JSON and XMLпринципы действия квот аналогичны.The quotas work similarly, using Mapping Between JSON and XML.

Безопасные средства чтения XMLSecure XML Readers

Информационный набор XML формирует базу обработки всех сообщений в WCF.The XML Infoset forms the basis of all message processing in WCF. Во время получения XML-данных из ненадежного источника существует вероятность применения ряда атак типа «отказ в обслуживании», которых следует избегать.When accepting XML data from an untrusted source, a number of denial-of-service attack possibilities exist that must be mitigated. WCF предоставляет специальные безопасные средства чтения XML.WCF provides special, secure XML readers. Эти модули чтения создаются автоматически при использовании одной из стандартных кодировок в WCF (Text, binary или MTOM).These readers are created automatically when using one of the standard encodings in WCF (text, binary, or MTOM).

Некоторые функции безопасности таких средств чтения включены постоянно.Some of the security features on these readers are always active. Например, средства чтения никогда не обрабатывают определения типов документа (DTD), которые являются потенциальным источником атак типа "отказ в обслуживании" и ни при каких условиях не должны появляться в допустимых сообщениях SOAP.For example, the readers never process document type definitions (DTDs), which are a potential source of denial-of-service attacks and should never appear in legitimate SOAP messages. Другие функции безопасности включают в себя квоты средства чтения, которые должны быть настроены (см. описание в следующем разделе).Other security features include reader quotas that must be configured, which are described in the following section.

При работе непосредственно с модулями чтения XML (например, при написании собственного пользовательского кодировщика или при работе непосредственно с Message классом) всегда используйте безопасные средства чтения WCF, если существует вероятность работы с ненадежными данными.When working directly with XML readers (such as when writing your own custom encoder or when working directly with the Message class), always use the WCF secure readers when there is a chance of working with untrusted data. Создайте безопасные средства чтения, вызвав одну из перегрузок статического фабричного метода CreateTextReader, CreateBinaryReaderили CreateMtomReader для класса XmlDictionaryReader .Create the secure readers by calling one of the static factory method overloads of CreateTextReader, CreateBinaryReader, or CreateMtomReader on the XmlDictionaryReader class. При создании средства чтения передайте безопасные значения квот.When creating a reader, pass in secure quota values. Не вызывайте перегрузки метода Create .Do not call the Create method overloads. Они не создают средство чтения WCF.These do not create a WCF reader. Вместо этого создается средство чтения, не защищенное функциями безопасности, описанными в этом разделе.Instead, a reader is created that is not protected by the security features described in this section.

Квоты средства чтенияReader Quotas

Для безопасных средств чтения XML предусмотрено пять настраиваемых квот.The secure XML readers have five configurable quotas. Они, как правило, задаются свойством ReaderQuotas для элементов привязки кодирования или стандартных привязок или с помощью объекта XmlDictionaryReaderQuotas , передаваемого при создании средства чтения.These are normally configured using the ReaderQuotas property on the encoding binding elements or standard bindings, or by using an XmlDictionaryReaderQuotas object passed when creating a reader.

MaxBytesPerReadMaxBytesPerRead

Эта квота ограничивает число байтов, которые считываются за одну операцию Read при чтении открывающего тега элемента и его атрибутов.This quota limits the number of bytes that are read in a single Read operation when reading the element start tag and its attributes. (В случае непотоковой передачи данных само имя элемента не учитывается в квоте.) MaxBytesPerRead важно по следующим причинам.(In non-streamed cases, the element name itself is not counted against the quota.) MaxBytesPerRead is important for the following reasons:

  • Во время чтения имя элемента и его атрибуты всегда буферизуются в память.The element name and its attributes are always buffered in memory when they are being read. Поэтому в режиме потоковой передачи важно правильно задать эту квоту, чтобы предотвратить чрезмерную буферизацию, если ожидается потоковая передача.Therefore, it is important to set this quota correctly in streaming mode to prevent excessive buffering when streaming is expected. Сведения о фактическом объеме буферизации см. в разделе квоты MaxDepth .See the MaxDepth quota section for information about the actual amount of buffering that takes place.

  • Наличие слишком большого числа атрибутов XML может привести к неоправданно большому времени обработки, поскольку требуется проверка уникальности имен атрибутов.Having too many XML attributes may use up disproportionate processing time because attribute names have to be checked for uniqueness. MaxBytesPerRead устраняет эту возможную проблему.MaxBytesPerRead mitigates this threat.

MaxDepthMaxDepth

Эта квота ограничивает максимальную глубину вложенности XML-элементов.This quota limits the maximum nesting depth of XML elements. Например, документ " <A> <B> <C/> </B> </A> " имеет глубину вложения, равную трем.For example, the document "<A><B><C/></B></A>" has a nesting depth of three. ЗначениеMaxDepth важно по следующим причинам.MaxDepth is important for the following reasons:

  • MaxDepth взаимодействует с MaxBytesPerRead: средство чтения всегда сохраняет в памяти данные по текущему элементу и всем его предкам, поэтому максимальный потребляемый средством чтения объем памяти пропорционален произведению этих двух параметров.MaxDepth interacts with MaxBytesPerRead: the reader always keeps data in memory for the current element and all of its ancestors, so the maximum memory consumption of the reader is proportional to the product of these two settings.

  • При десериализации графа объекта с глубоким вложением десериализатор принудительно получает доступ ко всему стеку, и выдается неисправимое исключение StackOverflowException.When deserializing a deeply-nested object graph, the deserializer is forced to access the entire stack and throw an unrecoverable StackOverflowException. Между вложением XML и вложением объекта существует прямая связь как для DataContractSerializer , так и для XmlSerializer.A direct correlation exists between XML nesting and object nesting for both the DataContractSerializer and the XmlSerializer. Квота MaxDepth позволяет устранить эту угрозу.Use MaxDepth to mitigate this threat.

MaxNameTableCharCountMaxNameTableCharCount

Эта квота ограничивает размер таблицы имен средства чтения.This quota limits the size of the reader’s nametable . В таблице имен содержатся определенные строки (например пространства имен и префиксы), возникающие при обработке документа XML.The nametable contains certain strings (such as namespaces and prefixes) that are encountered when processing an XML document. Поскольку эти строки буферизуются в память, задайте эту квоту, чтобы предотвратить чрезмерную буферизацию, если ожидается потоковая передача.As these strings are buffered in memory, set this quota to prevent excessive buffering when streaming is expected.

MaxStringContentLengthMaxStringContentLength

Эта квота ограничивает максимальный размер строки, возвращаемой средством чтения XML.This quota limits the maximum string size that the XML reader returns. Эта квота ограничивает потребление памяти не в самом средстве чтения XML, а в компоненте, использующем средство чтения.This quota does not limit memory consumption in the XML reader itself, but in the component that is using the reader. Например, когда DataContractSerializer использует средство чтения, защищенное MaxStringContentLength, он не десериализует строки, чей размер превышает указанное в этой квоте значение.For example, when the DataContractSerializer uses a reader secured with MaxStringContentLength, it does not deserialize strings larger than this quota. При непосредственном использовании класса XmlDictionaryReader не все методы учитывают эту квоту, а только те, которые специально созданы для чтения строк, например метод ReadContentAsString .When using the XmlDictionaryReader class directly, not all methods respect this quota, but only the methods that are specifically designed to read strings, such as the ReadContentAsString method. Эта квота не влияет на свойство Value средства чтения, и поэтому оно не должно использоваться, если требуется защита, обеспечиваемая этой квотой.The Value property on the reader is not affected by this quota, and thus should not be used when the protection this quota provides is necessary.

MaxArrayLengthMaxArrayLength

Эта квота ограничивает максимальный размер массива примитивов, возвращаемых средством чтения XML, включая байтовые массивы.This quota limits the maximum size of an array of primitives that the XML reader returns, including byte arrays. Эта квота ограничивает потребление памяти не в самом средстве чтения XML, а в компоненте, использующем средство чтения.This quota does not limit memory consumption in the XML reader itself, but in whatever component that is using the reader. Например, когда DataContractSerializer использует средство чтения, защищенное MaxArrayLength, оно не десериализует байтовые массивы, чей размер превышает указанное в этой квоте значение.For example, when the DataContractSerializer uses a reader secured with MaxArrayLength, it does not deserialize byte arrays larger than this quota. Важно задать эту квоту при попытке совместного использования моделей программирования потоковой передачи и буферизации в одном контракте.It is important to set this quota when attempting to mix streaming and buffered programming models in a single contract. Помните, что при непосредственном использовании класса XmlDictionaryReader этой квоте соответствуют только методы, специально созданные для чтения массивов произвольного размера определенных примитивных типов, например ReadInt32Array.Keep in mind that when using the XmlDictionaryReader class directly, only the methods that are specifically designed to read arrays of arbitrary size of certain primitive types, such as ReadInt32Array, respect this quota.

Угрозы, относящиеся к двоичному кодированиюThreats Specific to the Binary Encoding

Двоичная кодировка XML, поддерживаемая WCF, включает функцию строк словаря .The binary XML encoding WCF supports includes a dictionary strings feature. Большую строку можно закодировать с помощью всего нескольких байтов.A large string may be encoded using only a few bytes. В результате значительно повышается производительность, но при этом возникают новые угрозы атак типа "отказ в обслуживании", которые следует устранить.This enables significant performance gains, but introduces new denial-of-service threats that must be mitigated.

Существует два вида словарей: статический и динамический .There are two kinds of dictionaries: static and dynamic . Статический словарь представляет собой встроенный список длинных строк, которые можно представить с помощью короткого кода в двоичном кодировании.The static dictionary is a built-in list of long strings that may be represented using a short code in the binary encoding. При создании средства чтения список строк становится постоянным и не подлежит изменению.This list of strings is fixed when the reader is created and cannot be modified. Ни одна из строк в статическом словаре, которую WCF использует по умолчанию, достаточно велика, чтобы стать серьезной угрозой отказа в обслуживании, хотя они по-прежнему могут использоваться в атаке расширения словаря.None of the strings in the static dictionary that WCF uses by default are sufficiently large to pose a serious denial-of-service threat, although they may still be used in a dictionary expansion attack. В сложных сценариях, в которых используется собственный статический словарь, при вводе больших строк словаря следует соблюдать осторожность.In advanced scenarios where you supply your own static dictionary, be careful when introducing large dictionary strings.

Динамические словари позволяют сообщениям определять собственные строки и связывать их с сокращенными кодами.The dynamic dictionaries feature allows messages to define their own strings and associate them with short codes. Эти сопоставления "строка-код" хранятся в памяти во время всего сеанса связи, поэтому последующие сообщения не должны повторно отправлять строки и могут использовать уже определенные коды.These string-to-code mappings are kept in memory during the entire communication session, such that subsequent messages do not have to resend the strings and can utilize codes that are already defined. Эти строки могут быть произвольной длины, и поэтому представляют более серьезную угрозу по сравнению со строками статического словаря.These strings may be of arbitrary length and thus pose a more serious threat than those in the static dictionary.

Первой угрозой, которую следует устранить, является вероятность чрезмерного увеличения размера динамического словаря (таблицы сопоставлений "строка-код").The first threat that must be mitigated is the possibility of the dynamic dictionary (the string-to-code mapping table) becoming too large. Такой словарь может расширяться по мере накопления сообщений, а квота MaxReceivedMessageSize не обеспечивает защиту, поскольку применяется только к каждому отдельному сообщению.This dictionary may be expanded over the course of several messages, and so the MaxReceivedMessageSize quota offers no protection because it applies only to each message separately. Поэтому в MaxSessionSize существует отдельное свойство BinaryMessageEncodingBindingElement , ограничивающее размер словаря.Therefore, a separate MaxSessionSize property exists on the BinaryMessageEncodingBindingElement that limits the size of the dictionary.

В отличие от большинства других эта квота также применяется при записи сообщений.Unlike most other quotas, this quota also applies when writing messages. Если она превышается при чтении сообщения, как правило, выдается исключение QuotaExceededException .If it is exceeded when reading a message, the QuotaExceededException is thrown as usual. Если она превышается при записи сообщения, строки, ставшие причиной ее превышения, записываются "как есть", без использования функционала динамических словарей.If it is exceeded when writing a message, any strings that cause the quota to be exceeded are written as-is, without using the dynamic dictionaries feature.

Угрозы типа "расширение словаря"Dictionary Expansion Threats

Значительное число атак, относящихся к двоичному формату, относятся к расширению словаря.A significant class of binary-specific attacks arises from dictionary expansion. Небольшое сообщение в двоичной форме может стать очень большим сообщением в полностью развернутой текстовой форме, если оно активно использует строковую функцию словарей.A small message in binary form may turn into a very large message in fully expanded textual form if it makes extensive use of the string dictionaries feature. Коэффициент расширения строк динамического словаря ограничивается квотой MaxSessionSize , поскольку строка динамического словаря не превышает максимальный размер всего словаря.The expansion factor for dynamic dictionary strings is limited by the MaxSessionSize quota, because no dynamic dictionary string exceeds the maximum size of the entire dictionary.

Свойства MaxNameTableCharCount, MaxStringContentLengthи MaxArrayLength ограничивают только потребление памяти.The MaxNameTableCharCount, MaxStringContentLength, and MaxArrayLength properties only limit memory consumption. Как правило, они не требуются для устранения каких-либо угроз непотокового использования, поскольку выделение памяти уже ограничено MaxReceivedMessageSize.They are normally not required to mitigate any threats in the non-streamed usage because memory usage is already limited by MaxReceivedMessageSize. Однако MaxReceivedMessageSize учитывает байты предварительного расширения.However, MaxReceivedMessageSize counts pre-expansion bytes. При использовании двоичного кодирования потребление памяти потенциально может выйти за рамки MaxReceivedMessageSize, ограничиваясь только MaxSessionSize.When binary encoding is in use, memory consumption could potentially go beyond MaxReceivedMessageSize, limited only by a factor of MaxSessionSize. По этой причине, если используется двоичное кодирование, важно всегда задавать все квоты средства чтения (особенно MaxStringContentLength).For this reason, it is important to always set all of the reader quotas (especially MaxStringContentLength) when using the binary encoding.

При использовании двоичного кодирования наряду с DataContractSerializerвозможно неправильное использование интерфейса IExtensibleDataObject , что может вызвать атаку типа "расширение словаря".When using binary encoding together with the DataContractSerializer, the IExtensibleDataObject interface can be misused to mount a dictionary expansion attack. По существу этот интерфейс предоставляет неограниченное пространство для произвольных данных, не являющихся частью контракта.This interface essentially provides unlimited storage for arbitrary data that is not a part of the contract. Если невозможно задать достаточно низкие квоты, чтобы произведение MaxSessionSize и MaxReceivedMessageSize не представляло бы проблемы, при использовании двоичного кодирования отключите функцию IExtensibleDataObject .If quotas cannot be set low enough such that MaxSessionSize multiplied by MaxReceivedMessageSize does not pose a problem, disable the IExtensibleDataObject feature when using the binary encoding. Задайте для свойства IgnoreExtensionDataObject значение true для атрибута ServiceBehaviorAttribute .Set the IgnoreExtensionDataObject property to true on the ServiceBehaviorAttribute attribute. В качестве альтернативы можно не реализовывать интерфейс IExtensibleDataObject .Alternatively, do not implement the IExtensibleDataObject interface. Дополнительные сведения о создании контрактов данных, обладающих прямой совместимостью, см. в разделе Контракты данных, совместимые с любыми будущими изменениями.For more information, see Forward-Compatible Data Contracts.

Сводка по квотамQuotas Summary

В следующей таблице приводятся сводные правила использования квот.The following table summarizes the guidance about quotas.

УсловиеCondition Важные квоты, которые следует задатьImportant quotas to set
Отсутствие потоковой передачи или потоковая передача небольших сообщений, кодирование text или MTOMNo streaming or streaming small messages, text, or MTOM encoding MaxReceivedMessageSize, MaxBytesPerRead и MaxDepth.MaxReceivedMessageSize, MaxBytesPerRead, and MaxDepth
Отсутствие потоковой передачи или потоковая передача небольших сообщений, двоичное кодированиеNo streaming or streaming small messages, binary encoding MaxReceivedMessageSize, MaxSessionSizeи все ReaderQuotasMaxReceivedMessageSize, MaxSessionSize, and all ReaderQuotas
Потоковая передача больших сообщений, текстовое кодирование или кодирование MTOMStreaming large messages, text, or MTOM encoding MaxBufferSize и все ReaderQuotasMaxBufferSize and all ReaderQuotas
Потоковая передача больших сообщений, двоичное кодированиеStreaming large messages, binary encoding MaxBufferSize, MaxSessionSizeи все ReaderQuotasMaxBufferSize, MaxSessionSize, and all ReaderQuotas
  • Всегда должны быть заданы значения времени ожидания на транспортном уровне, запрещается синхронное чтение/запись при использовании потоковой передачи независимо от того, какие сообщения передаются потоком: большие или малые.Transport-level time-outs must always be set and never use synchronous reads/writes when streaming is in use, regardless of whether you are streaming large or small messages.

  • В случае возникновения сомнений в отношении квот задавайте безопасное значение, но не оставляйте их пустыми.When in doubt about a quota, set it to a safe value rather than leaving it open.

Предотвращение выполнения вредоносного кодаPreventing Malicious Code Execution

Угрозы следующих общих классов могут выполнять код и приводить к незапланированным последствиям.The following general classes of threats can execute code and have unintended effects:

  • Десериализатор загружает вредоносный, небезопасный тип или тип, относящийся к безопасности.The deserializer loads a malicious, unsafe, or security-sensitive type.

  • Входящее сообщение заставляет десериализатор создавать экземпляр безопасного в нормальных условиях типа, который приведет к нежелательным последствиям.An incoming message causes the deserializer to construct an instance of a normally safe type in such a way that it has unintended consequences.

В следующих разделах приводится подробное описание таких классов угроз.The following sections discuss these classes of threats further.

DataContractSerializerDataContractSerializer

(Сведения о безопасности см XmlSerializer . в соответствующей документации.) Модель безопасности для элемента XmlSerializer аналогична модели DataContractSerializer , и в основном отличается главными деталями.(For security information on the XmlSerializer, see the relevant documentation.) The security model for the XmlSerializer is similar to that of the DataContractSerializer, and differs mostly in details. Например, для включения типа используется атрибут XmlIncludeAttribute вместо атрибута KnownTypeAttribute .For example, the XmlIncludeAttribute attribute is used for type inclusion instead of the KnownTypeAttribute attribute. Однако далее в этой теме рассматриваются угрозы, уникальные для XmlSerializer .However, some threats unique to the XmlSerializer are discussed later in this topic.

Предотвращение загрузки непредусмотренных типовPreventing Unintended Types from Being Loaded

Загрузка непредусмотренных типов может привести к серьезным последствиям, будь этот тип вредоносным или всего лишь косвенно влияющим на безопасность.Loading unintended types may have significant consequences, whether the type is malicious or just has security-sensitive side effects. Тип может содержать уязвимость системы безопасности, выполнять действия, относящиеся к безопасности, в конструкторе или конструкторе класса, занимать большой объем памяти, что способствует атакам типа "отказ в обслуживании", или выводить неустранимые исключения.A type may contain exploitable security vulnerability, perform security-sensitive actions in its constructor or class constructor, have a large memory footprint that facilitates denial-of-service attacks, or may throw non-recoverable exceptions. Типы могут содержать конструкторы классов, которые начинают работать сразу после загрузки типа и до создания каких-либо экземпляров.Types may have class constructors that run as soon as the type is loaded and before any instances are created. По этим причинам важно контролировать набор типов, которые может загружать десериализатор.For these reasons, it is important to control the set of types that the deserializer may load.

DataContractSerializer выполняет десериализацию слабо связанным образом.The DataContractSerializer deserializes in a loosely coupled way. Он никогда не считывает тип среды CLR и имена сборок из входящих данных.It never reads common language runtime (CLR) type and assembly names from the incoming data. Такое поведение аналогично поведению XmlSerializer, но отличается от поведения NetDataContractSerializer, BinaryFormatterи SoapFormatter.This is similar to the behavior of the XmlSerializer, but differs from the behavior of the NetDataContractSerializer, BinaryFormatter, and the SoapFormatter. Слабое связывание предполагает некоторый уровень безопасности, поскольку удаленный злоумышленник не может указать произвольный тип, чтобы выполнить загрузку только путем именования этого типа в сообщении.Loose coupling introduces a degree of safety, because the remote attacker cannot indicate an arbitrary type to load just by naming that type in the message.

Для DataContractSerializer всегда разрешено загружать тип, который в текущий момент ожидается в соответствии с контрактом.The DataContractSerializer is always allowed to load a type that is currently expected according to the contract. Например, если контракт данных содержит элемент данных типа Customer, для DataContractSerializer разрешено загрузить тип Customer , когда он выполняет десериализацию этого элемента данных.For example, if a data contract has a data member of type Customer, the DataContractSerializer is allowed to load the Customer type when it deserializes this data member.

Кроме того, DataContractSerializer поддерживает полиморфизм.Additionally, the DataContractSerializer supports polymorphism. Элемент данных может быть объявлен как Object, но входящие данные могут содержать экземпляр Customer .A data member may be declared as Object, but the incoming data may contain a Customer instance. Такое возможно только, если тип Customer был отмечен для десериализатора как "известный" посредством одного из следующих механизмов:This is possible only if the Customer type has been made "known" to the deserializer through one of these mechanisms:

  • атрибутKnownTypeAttribute , примененный к типу;KnownTypeAttribute attribute applied to a type.

  • атрибутKnownTypeAttribute , указывающий метод, который возвращает список типов;KnownTypeAttribute attribute specifying a method that returns a list of types.

  • атрибутServiceKnownTypeAttribute .ServiceKnownTypeAttribute attribute.

  • раздел конфигурации KnownTypes ;The KnownTypes configuration section.

  • список известных типов, явно переданных в DataContractSerializer во время создания при непосредственном использовании сериализатора.A list of known types explicitly passed to the DataContractSerializer during construction, if using the serializer directly.

Каждый из этих механизмов увеличивает контактную зону, представляя большее число типов, которое может загрузить десериализатор.Each of these mechanisms increases the surface area by introducing more types that the deserializer can load. Каждый из этих механизмов требует контроля, чтобы предотвратить добавление вредоносных или непредусмотренных типов в список известных.Control each of these mechanisms to ensure no malicious or unintended types are added to the known types list.

Когда известный тип находится в области, его можно загрузить в любой момент времени, и можно создать экземпляры типа, даже если контракт запрещает его фактическое использование.Once a known type is in scope, it can be loaded at any time, and instances of the type can be created, even if the contract forbids actually using it. Например, допустим, что тип "MyDangerousType" добавлен в список известных типов с помощью одного из указанных выше механизмов.For example, suppose the type "MyDangerousType" is added to the known types list using one of the mechanisms above. Это означает следующее:This means that:

  • ЗагружаетсяMyDangerousType , и запускается его конструктор класса.MyDangerousType is loaded and its class constructor runs.

  • Даже при десериализации контракта данных с элементом данных строки вредоносное сообщение все равно может создать экземпляр MyDangerousType .Even when deserializing a data contract with a string data member, a malicious message may still cause an instance of MyDangerousType to create. Возможно выполнение кода в MyDangerousType(например в методах задания свойств).Code in MyDangerousType, such as property setters, may run. По окончании десериализатор пытается назначить этот экземпляр для элемента данных строки и завершает работу с выводом исключения.After this is done, the deserializer tries to assign this instance to the string data member and fail with an exception.

При записи метода, возвращающего список известных типов, или при передаче списка непосредственно в конструктор DataContractSerializer убедитесь, что подготавливающий список код безопасен и работает только с надежными данными.When writing a method that returns a list of known types, or when passing a list directly to the DataContractSerializer constructor, ensure that the code that prepares the list is secure and operates only on trusted data.

При указании известных типов в конфигурации убедитесь, что файл конфигурации защищен.If specifying known types in configuration, ensure that the configuration file is secure. В конфигурации всегда используйте строгие имена (указывая открытый ключ подписанной сборки, в которой расположен тип), но не указывайте версию загружаемого типа.Always use strong names in configuration (by specifying the public key of the signed assembly where the type resides), but do not specify the version of the type to load. Загрузчик типов автоматически выбирает последнюю версию, если это возможно.The type loader automatically picks the latest version, if possible. Если в конфигурации указана определенная версия, существует следующий риск: тип может иметь уязвимость системы безопасности, которая может быть устранена в следующей версии, но версия с уязвимостью все равно выполняет загрузку, поскольку она явно указана в конфигурации.If you specify a particular version in configuration, you run the following risk: A type may have a security vulnerability that may be fixed in a future version, but the vulnerable version still loads because it is explicitly specified in configuration.

При наличии слишком большого числа известных типов возникает другое следствие: DataContractSerializer создает кэш кода сериализации/десериализации в домене приложения с записью для каждого типа, который требуется сериализовать или десериализовать.Having too many known types has another consequence: The DataContractSerializer creates a cache of serialization/deserialization code in the application domain, with an entry for each type it must serialize and deserialize. Этот кэш никогда не очищается, пока работает домен приложения.This cache is never cleared as long as the application domain is running. Поэтому злоумышленник, знающий, что приложение использует большое число известных типов, может вызвать десериализацию всех этих типов, в результате чего кэш будет использовать неограниченный объем памяти.Therefore, an attacker who is aware that an application uses many known types can cause the deserialization of all these types, causing the cache to consume a disproportionately large amount of memory.

Избежание непредусмотренного состояния типовPreventing Types from Being in an Unintended State

Тип может иметь внутренние ограничения согласованности, которые обязательны к соблюдению.A type may have internal consistency constraints that must be enforced. Следует соблюдать осторожность, чтобы не нарушить эти ограничения во время десериализации.Care must be taken to avoid breaking these constraints during deserialization.

В следующем примере типа представлено состояние шлюза космического корабля и соблюдение ограничения, при котором внутренняя и внешняя двери не могут быть открыты одновременно.The following example of a type represents the state of an airlock on a spacecraft, and enforces the constraint that both the inner and the outer doors cannot be open at the same time.

[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

Злоумышленник может отправить вредоносное сообщение наподобие этого, обойти ограничения и привести объект в недопустимое состояние, результатом чего будут непредусмотренные и непредсказуемые последствия.An attacker may send a malicious message like this, getting around the constraints and getting the object into an invalid state, which may have unintended and unpredictable consequences.

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

Такой ситуации можно избежать, если учитывать следующие моменты.This situation can be avoided by being aware of the following points:

  • Когда DataContractSerializer десериализует большинство классов, конструкторы не работают.When the DataContractSerializer deserializes most classes, constructors do not run. Поэтому не следует полагаться на какое-либо управление состоянием, осуществленное в конструкторе.Therefore, do not rely on any state management done in the constructor.

  • Чтобы убедиться в действительном состоянии объекта, используйте обратные вызовы.Use callbacks to ensure that the object is in a valid state. Обратный вызов, отмеченный атрибутом OnDeserializedAttribute , особенно полезен, поскольку он запускается по завершении сериализации и позволяет изучить и исправить общее состояние.The callback marked with the OnDeserializedAttribute attribute is especially useful because it runs after deserialization is complete and has a chance to examine and correct the overall state. Дополнительные сведения см. в разделе обратные вызовы сериализации с поддержкой версий.For more information, see Version-Tolerant Serialization Callbacks.

  • Не создавайте типы контрактов данных, полагаясь на какой-либо определенный порядок, в котором требуется вызов методов задания свойств.Do not design data contract types to rely on any particular order in which property setters must be called.

  • Соблюдайте осторожность при использовании устаревших типов, отмеченных атрибутом SerializableAttribute .Take care using legacy types marked with the SerializableAttribute attribute. Многие из них предназначены для работы с .NET Framework удаленным взаимодействием для использования только с доверенными данными.Many of them were designed to work with .NET Framework remoting for use with trusted data only. Существующие типы, отмеченные этим атрибутом, могут быть созданы и без учета обеспечения безопасности состояния.Existing types marked with this attribute may not have been designed with state safety in mind.

  • Чтобы гарантировать наличие данных с учетом обеспечения безопасности состояния, не следует полагаться на свойство IsRequired атрибута DataMemberAttribute .Do not rely on the IsRequired property of the DataMemberAttribute attribute to guarantee presence of data as far as state safety is concerned. Данные всегда могут быть null, zeroили invalid.Data could always be null, zero, or invalid.

  • Никогда не доверяйте графу объекта, десериализованному из источника ненадежных данных, не определив сначала его действительность.Never trust an object graph deserialized from an untrusted data source without validating it first. Каждый отдельный объект может находиться в согласованном состоянии, однако весь граф объекта в таком состоянии может и не находиться.Each individual object may be in a consistent state, but the object graph as a whole may not be. Более того, даже если выключен режим сохранения графа объекта, десериализованный граф может содержать несколько ссылок на небольшой объект или содержать циклические ссылки.Furthermore, even if the object graph preservation mode is disabled, the deserialized graph may have multiple references to the same object or have circular references. Дополнительные сведения см. в разделе сериализация и десериализация.For more information, see Serialization and Deserialization.

Безопасное использование NetDataContractSerializerUsing the NetDataContractSerializer Securely

NetDataContractSerializer представляет собой ядро сериализации, использующее тесное соединение с типами.The NetDataContractSerializer is a serialization engine that uses tight coupling to types. Это аналогично BinaryFormatter и SoapFormatter.This is similar to the BinaryFormatter and the SoapFormatter. То есть он определяет, какой тип следует создать, путем считывания .NET Framework сборки и имени типа из входящих данных.That is, it determines which type to instantiate by reading the .NET Framework assembly and type name from the incoming data. Хотя это и является частью WCF, не существует способа подключения этого механизма сериализации. необходимо написать пользовательский код.Although it is a part of WCF, there is no supplied way of plugging in this serialization engine; custom code must be written. NetDataContractSerializerПредоставляется в основном для упрощения миграции с .NET Framework удаленного взаимодействия в WCF.The NetDataContractSerializer is provided primarily to ease migration from .NET Framework remoting to WCF. Дополнительные сведения см. в соответствующем разделе, посвященном сериализации и десериализации.For more information, see the relevant section in Serialization and Deserialization.

Поскольку само сообщение может указывать любой тип, который можно загрузить, механизм NetDataContractSerializer по своей природе небезопасен и должен использоваться только с надежными данными.Because the message itself may indicate any type can be loaded, the NetDataContractSerializer mechanism is inherently insecure and should be used only with trusted data. Дополнительные сведения см. в разделе BinaryFormatter Security Guide.For more information, see the BinaryFormatter security guide.

Даже при использовании с надежными данными входящие данные могут недостаточно точно указывать загружаемый тип, особенно если свойство AssemblyFormat задано как Simple.Even when used with trusted data, the incoming data may insufficiently specify the type to load, especially if the AssemblyFormat property is set to Simple. Любой, у кого есть доступ к каталогу приложения или глобальному кэшу сборок, может заменить один из загружаемых типов вредоносным.Anyone with access to the application’s directory or to the global assembly cache can substitute a malicious type in place of the one that is supposed to load. Всегда защищайте каталог приложения и глобальный кэш сборок, правильно назначая разрешения.Always ensure the security of your application’s directory and of the global assembly cache by correctly setting permissions.

В общем, если открыть для частично доверенного кода доступ к своему экземпляру NetDataContractSerializer или иным образом разрешить ему управление суррогатным селектором (ISurrogateSelector) или связывателем сериализации (SerializationBinder), код может получить значительные возможности управления процессом сериализации/десериализации.In general, if you allow partially trusted code access to your NetDataContractSerializer instance or otherwise control the surrogate selector (ISurrogateSelector) or the serialization binder (SerializationBinder), the code may exercise a great deal of control over the serialization/deserialization process. Например, он может ввести произвольные типы, привести к раскрытию информации, подделать получаемый граф объекта или сериализованные данные или переполнить итоговый сериализованный поток.For example, it may inject arbitrary types, lead to information disclosure, tamper with the resulting object graph or serialized data, or overflow the resultant serialized stream.

Еще одним вопросом безопасности, связанным с NetDataContractSerializer , является отказ от обслуживания, не угроза выполнения вредоносного кода.Another security concern with the NetDataContractSerializer is a denial of service, not a malicious code execution threat. При использовании NetDataContractSerializerвсегда задавайте для квоты MaxItemsInObjectGraph безопасное значение.When using the NetDataContractSerializer, always set the MaxItemsInObjectGraph quota to a safe value. Очень просто создать небольшое вредоносное сообщение, выделяющее массив объектов, чей размер ограничен только этой квотой.It is easy to construct a small malicious message that allocates an array of objects whose size is limited only by this quota.

Угрозы, связанные с XmlSerializerXmlSerializer-Specific Threats

Модель безопасности XmlSerializer аналогична модели DataContractSerializer.The XmlSerializer security model is similar to that of the DataContractSerializer. Однако существует несколько угроз, уникальных для XmlSerializer.A few threats, however, are unique to the XmlSerializer.

XmlSerializer во время выполнения создает сборки сериализации , содержащие код, который фактически выполняет сериализацию и десериализацию. Эти сборки создаются в каталоге временных файлов.The XmlSerializer generates serialization assemblies at runtime that contain code that actually serializes and deserializes; these assemblies are created in a temporary files directory. Если любой другой процесс или пользователь получают доступ к этому каталогу, он может перезаписать код сериализации/десериализации произвольным кодом.If some other process or user has access rights to that directory, they may overwrite the serialization/deserialization code with arbitrary code. Затем XmlSerializer выполняет этот код с использованием его контекста безопасности вместо кода сериализации/десериализации.The XmlSerializer then runs this code using its security context, instead of the serialization/deserialization code. Убедитесь, что для каталога временных файлов правильно заданы разрешения, чтобы избежать такой ситуации.Make sure the permissions are set correctly on the temporary files directory to prevent this from happening.

Для XmlSerializer также предусмотрен режим, в котором он использует заранее созданные сборки сериализации вместо того, чтобы создавать их в процессе выполнения.The XmlSerializer also has a mode in which it uses pre-generated serialization assemblies instead of generating them at runtime. Этот режим включается в каждом случае, когда XmlSerializer обнаруживает подходящую сборку сериализации.This mode is triggered whenever the XmlSerializer can find a suitable serialization assembly. XmlSerializer проверяет, была ли сборка сериализации подписана тем же ключом, который использовался для подписи сборки, содержащей сериализуемые типы.The XmlSerializer checks whether or not the serialization assembly was signed by the same key that was used to sign the assembly that contains the types being serialized. Это обеспечивает защиту от вредоносных сборок, маскирующихся под сборки сериализации.This offers protection from malicious assemblies being disguised as serialization assemblies. Однако если сборка, содержащая сериализуемые типы, не подписана, XmlSerializer не может это проверить и использует любую сборку с правильным именем.However, if the assembly that contains your serializable types is not signed, the XmlSerializer cannot perform this check and uses any assembly with the correct name. Это сделает возможным выполнение вредоносного кода.This makes running malicious code possible. Всегда подписывайте сборки, содержащие сериализуемые типы, или тщательно контролируйте доступ к каталогу приложения и глобальному кэшу сборок, чтобы предотвратить появление вредоносных сборок.Always sign the assemblies that contain your serializable types, or tightly control access to your application’s directory and the global assembly cache to prevent the introduction of malicious assemblies.

XmlSerializer может подвергаться атаке типа "отказ в обслуживании".The XmlSerializer can be subject to a denial of service attack. У XmlSerializer отсутствует квота MaxItemsInObjectGraph (которая предусмотрена для DataContractSerializer).The XmlSerializer does not have a MaxItemsInObjectGraph quota (as is available on the DataContractSerializer). Поэтому он десериализует произвольное число объектов, ограничиваясь только размером сообщения.Thus, it deserializes an arbitrary amount of objects, limited only by the message size.

Угрозы частичного доверияPartial Trust Threats

Обратите внимание на следующие проблемы, связанные с угрозами, которые относятся к коду, выполняемому с частичным доверием.Note the following concerns regarding threats related to code running with partial trust. Эти угрозы включают в себя вредоносный частично доверенный код, а также такой код в сочетании с другими сценариями атак (например частично доверенный код, создающий определенную строку, а затем ее десериализующий).These threats include malicious partially-trusted code as well as malicious partially-trusted code in combination with other attack scenarios (for example, partially-trusted code that constructs a specific string and then deserializing it).

  • При использовании любых компонентов сериализации никогда не назначайте какие-либо разрешения до начала такого использования, даже если весь сценарий сериализации находится в рамках назначения, и используются только доверенные данные и объекты.When using any serialization components, never assert any permissions before such usage, even if the entire serialization scenario is within the scope of your assert, and you are not dealing with any untrusted data or objects. Такое использование может стать причиной уязвимостей системы безопасности.Such usage may lead to security vulnerabilities.

  • В случаях, когда частично доверенный код управляет процессом сериализации посредством точек расширяемости (суррогатов), сериализуемых типов или иными способами, такой код может заставить сериализатор вывести большой объем данных в сериализованный поток, что может стать причиной отказа в обслуживании (DoS) получателя этого потока.In cases where partially-trusted code has control over the serialization process, either through extensibility points (surrogates), types being serialized, or through other means, the partially-trusted code may cause the serializer to output a large amount of data into the serialized stream, which may cause Denial of Service (DoS) to the receiver of this stream. При сериализации данных, предназначенных для целевого объекта, не защищенного от угроз DoS, не сериализуйте частично доверенные типы или не допускайте, чтобы частично доверенный код каким-либо образом управлял сериализацией.If you are serializing data intended for a target that is sensitive to DoS threats, do not serialize partially-trusted types or otherwise let partially-trusted code control serialization.

  • Если вы разрешаете частично доверенный код доступ к вашему DataContractSerializer экземпляру или иным образом контролируете суррогаты контракта данных, это может привести к значительному управлению процессом сериализации и десериализации.If you allow partially-trusted code access to your DataContractSerializer instance or otherwise control the Data Contract Surrogates, it may exercise a great deal of control over the serialization/deserialization process. Например, он может ввести произвольные типы, привести к раскрытию информации, подделать получаемый граф объекта или сериализованные данные или переполнить итоговый сериализованный поток.For example, it may inject arbitrary types, lead to information disclosure, tamper with the resulting object graph or serialized data, or overflow the resultant serialized stream. Аналогичная угроза для NetDataContractSerializer описана в разделе "Безопасное использование NetDataContractSerializer".An equivalent NetDataContractSerializer threat is described in the "Using the NetDataContractSerializer Securely" section.

  • Если атрибут DataContractAttribute применяется к типу (или типу, отмеченному SerializableAttribute , но не ISerializable), десериализатор может создать экземпляр такого типа, даже если все конструкторы являются закрытыми или защищены требованиями.If the DataContractAttribute attribute is applied to a type (or the type marked as SerializableAttribute but is not ISerializable), the deserializer can create an instance of such a type even if all constructors are non-public or protected by demands.

  • Ни при каких обстоятельствах не следует доверять результату десериализации, пока сериализуемые данные не будут надежными, и все известные типы не будут именно теми типами, которым можно доверять.Never trust the result of deserialization unless the data to be deserialized is trusted and you are certain that all known types are types that you trust. Обратите внимание, что известные типы не загружаются из файла конфигурации приложения (а загружаются из файла конфигурации компьютера) во время работы с частичным уровнем доверия.Note that known types are not loaded from the application configuration file, (but are loaded from the computer configuration file) when running in partial trust.

  • Если передается экземпляр DataContractSerializer с суррогатом, добавленным в частично доверенный код, код может изменить любые изменяемые параметры этого суррогата.If you pass a DataContractSerializer instance with a surrogate added to partially-trusted code, the code can change any modifiable settings on that surrogate.

  • Что касается десериализованного объекта, если средство чтения XML (или данных) используется с частично доверенным кодом, считайте полученный десериализованный объект ненадежным.For a deserialized object, if the XML reader (or the data therein) comes from partially-trusted code, treat the resulting deserialized object as untrusted data.

  • Тот факт, что у типа ExtensionDataObject отсутствуют открытые элементы, не означает, что его данные защищены.The fact that the ExtensionDataObject type has no public members does not mean that data within it is secure. Например, если выполняется десериализация из источника привилегированных данных в объект, содержащий некоторое количество данных, а затем этот объект передается частично доверенному коду, этот код может считать данные в ExtensionDataObject путем сериализации объекта.For example, if you deserialize from a privileged data source into an object in which some data resides, then hand that object to partially-trusted code, the partially-trusted code can read the data in the ExtensionDataObject by serializing the object. Рассмотрите возможность задания параметра IgnoreExtensionDataObject как true при десериализации из источника привилегированных данных в объект, который затем передается частично доверенному коду.Consider setting IgnoreExtensionDataObject to true when deserializing from a privileged data source into an object that is later passed to partially-trusted code.

  • DataContractSerializer и DataContractJsonSerializer поддерживают сериализацию частных, защищенных, внутренних и открытых членов в условиях полного доверия.DataContractSerializer and DataContractJsonSerializer support the serialization of private, protected, internal, and public members in full trust. Однако в среде с частичным уровнем доверия возможна сериализация только открытых членов.However, in partial trust, only public members can be serialized. Если приложение пытается сериализировать член, отличный от открытого, вызывается SecurityException .A SecurityException is thrown if an application attempts to serialize a non-public member.

    Чтобы сериализировать внутренние или защищенные внутренние члены в условиях частичного уровня доверия, используйте атрибут сборки InternalsVisibleToAttribute .To allow internal or protected internal members to be serialized in partial trust, use the InternalsVisibleToAttribute assembly attribute. Этот атрибут позволяет сборке объявлять, что ее внутренние элементы являются видимыми для некоторых других сборок.This attribute allows an assembly to declare that its internal members are visible to some other assembly. В этом случае сборка, внутренние члены которой нужно сериализировать, объявляет свои внутренние члены видимыми для System.Runtime.Serialization.dll.In this case, an assembly that wants to have its internal members serialized declares that its internal members are visible to System.Runtime.Serialization.dll.

    Преимущество такого подхода состоит в том, что не требуется путь создания кода с повышенными привилегиями.The advantage of this approach is that it does not require an elevated code generation path.

    Но есть у него и два существенных недостатка.At the same time, there are two major disadvantages.

    Первый заключается в том, что включаемое по требованию свойство атрибута InternalsVisibleToAttribute действует на уровне сборки.The first disadvantage is that the opt-in property of the InternalsVisibleToAttribute attribute is assembly-wide. Следовательно, нельзя разрешить сериализацию внутренних членов только одного определенного класса.That is, you cannot specify that only a certain class can have its internal members serialized. Чтобы не сериализировать любой конкретный внутренний член, достаточно не добавлять к нему атрибут DataMemberAttribute .Of course, you can still choose not to serialize a specific internal member, by simply not adding a DataMemberAttribute attribute to that member. Аналогично разработчик может сделать член внутренним, а не частным или защищенным, немного затруднив обеспечение видимости.Similarly, a developer can also choose to make a member internal rather than private or protected, with slight visibility concerns.

    Второй недостаток заключается в том, что частные и защищенные члены все еще не поддерживаются.The second disadvantage is that it still does not support private or protected members.

    В качестве иллюстрации использования атрибута InternalsVisibleToAttribute в условиях частичного уровня доверия может послужить следующая программа:To illustrate the use of the InternalsVisibleToAttribute attribute in partial trust, consider the following program:

        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 для частичного уровня доверия.In the example above, PermissionsHelper.InternetZone corresponds to the PermissionSet for partial trust. Теперь, без InternalsVisibleToAttribute атрибута, приложение завершится ошибкой, вызывая исключение, SecurityException указывающее, что не являющиеся открытыми члены не могут быть сериализованы при частичном доверии.Now, without the InternalsVisibleToAttribute attribute, the application will fail, throwing a SecurityException indicating that non-public members cannot be serialized in partial trust.

    Однако, если добавить в исходный код следующую строку, программа будет выполнена успешно.However, if we add the following line to the source file, the program runs successfully.

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

Другие вопросы управления состояниемOther State Management Concerns

Следует упомянуть еще ряд соображений касательно управления состоянием объекта.A few other concerns regarding object state management are worth mentioning:

  • При использовании модели программирования, основанной на потоковой передаче, с потоковым каналом транспорта сообщение обрабатывается после его получения.When using the stream-based programming model with a streaming transport, processing of the message occurs as the message arrives. Отправитель сообщения может отменить операцию отправки посередине потока, оставив код в непредсказуемом состоянии, если планировалась передача большего содержимого.The sender of the message may abort the send operation in the middle of the stream, leaving your code in an unpredictable state if more content was expected. В целом не следует полагаться на завершаемый поток и выполнять какие-либо действия по операции, основанной на потоке, для которых невозможно выполнить откат в случае отмены потока.In general, do not rely on the stream being complete, and do not perform any work in a stream-based operation that cannot be rolled back in case the stream is aborted. Это также применимо к ситуации, когда сообщение может быть неправильно сформировано после потокового тела (например, в нем может отсутствовать закрывающий тег конверта SOAP или может присутствовать второе тело сообщения).This also applies to the situation where a message may be malformed after the streaming body (for example, it may be missing an end tag for the SOAP envelope or may have a second message body).

  • Использование функции IExtensibleDataObject может привести к раскрытию конфиденциальных данных.Using the IExtensibleDataObject feature may cause sensitive data to be emitted. При принятии данных из недоверенного источника в контракты данных с IExtensibleObjectData и последующим повторным их раскрытием для безопасного канала, в котором подписываются сообщения, данные, о которых ничего не известно, потенциально подтверждаются.If you are accepting data from an untrusted source into data contracts with IExtensibleObjectData and later re-emitting it on a secure channel where messages are signed, you are potentially vouching for data you know nothing about. Более того, отправляемое общее состояние может быть недействительным, если в учетную запись передаются известные и неизвестные блоки данных.Moreover, the overall state you are sending may be invalid if you take both the known and unknown pieces of data into account. Такой ситуации можно избежать, выборочно задав свойство расширения данных как null или выборочно отключив функцию IExtensibleObjectData .Avoid this situation by either selectively setting the extension data property to null or by selectively disabling the IExtensibleObjectData feature.

Импорт схемыSchema Import

Как правило, процедура импорта схемы для создания типов выполняется только на этапе разработки, когда для создания класса клиента в веб-службе используется ServiceModel Metadata Utility Tool (Svcutil.exe) .Normally, the process of importing schema to generate types happens only at design time, for example, when using the ServiceModel Metadata Utility Tool (Svcutil.exe) on a Web service to generate a client class. Однако в более сложных сценариях схему можно обработать во время выполнения.However, in more advanced scenarios, you may process schema at runtime. Помните, что такая процедура может стать причиной атак типа "отказ в обслуживании".Be aware that doing so can expose you to denial-of-service risks. Импортирование некоторых схем может занять много времени.Some schema may take a long time to be imported. Никогда не используйте в таких сценариях компонент импорта схемы XmlSerializer , если схемы могут происходить из недоверенного источника.Never use the XmlSerializer schema import component in such scenarios if schemas are possibly coming from an untrusted source.

Угрозы, относящиеся к интеграции ASP.NET AJAXThreats Specific to ASP.NET AJAX Integration

Когда пользователь реализует интерфейс WebScriptEnablingBehavior или WebHttpBehavior , WCF предоставляет конечную точку, которая может принимать сообщения XML и JSON.When the user implements WebScriptEnablingBehavior or WebHttpBehavior, WCF exposes an endpoint that can accept both XML and JSON messages. Однако существует только один набор квот средства чтения, используемых средствами чтения XML и JSON.However, there is only one set of reader quotas, used both by the XML reader and the JSON reader. Некоторые параметры квот могут подходить для одного средства чтения, но при этом быть слишком большими для другого.Some quota settings may be appropriate for one reader but too large for the other.

При реализации WebScriptEnablingBehaviorпользователю предоставляется вариант раскрытия прокси JavaScript в конечной точке.When implementing WebScriptEnablingBehavior, the user has the option to expose a JavaScript proxy at the endpoint. Следует принимать во внимание следующие вопросы безопасности.The following security issues must be considered:

  • Информацию о службе (имена операций, параметров и т. д.) можно получить, изучив прокси JavaScript.Information about the service (operation names, parameter names, and so on) can be obtained by examining the JavaScript proxy.

  • При использовании конечной точки JavaScript конфиденциальная и важная информация может сохраняться в кэше веб-браузера клиента.When using the JavaScript endpoint, sensitive and private information might be retained in the client Web browser cache.

Замечание по компонентамA Note on Components

WCF — это гибкая и настраиваемая система.WCF is a flexible and customizable system. Большая часть содержимого этого раздела сосредоточена на наиболее распространенных сценариях использования WCF.Most of the contents of this topic focus on the most common WCF usage scenarios. Однако компоненты, предоставляемые WCF, можно составить различными способами.However, it is possible to compose components WCF provides in many different ways. Важно понимать последствия нарушения безопасности при использовании каждого компонента.It is important to understand the security implications of using each component. В частности:In particular:

  • Если требуется использование средств чтения XML, используйте средства чтения, обеспечиваемые классом XmlDictionaryReader , а не любые другие средства чтения.When you must use XML readers, use the readers the XmlDictionaryReader class provides as opposed to any other readers. Безопасные средства чтения создаются с помощью методов CreateTextReader, CreateBinaryReaderили CreateMtomReader .Safe readers are created using CreateTextReader, CreateBinaryReader, or CreateMtomReader methods. Не используйте метод Create .Do not use the Create method. Для средств чтения всегда задавайте безопасные квоты.Always configure the readers with safe quotas. Механизмы сериализации в WCF защищены только при использовании с защищенными модулями чтения XML из WCF.The serialization engines in WCF are secure only when used with secure XML readers from WCF.

  • Если для десериализации потенциально ненадежных данных используется DataContractSerializer , всегда задавайте свойство MaxItemsInObjectGraph .When using the DataContractSerializer to deserialize potentially untrusted data, always set the MaxItemsInObjectGraph property.

  • При создании сообщения задавайте параметр maxSizeOfHeaders , если MaxReceivedMessageSize не обеспечивает достаточный уровень защиты.When creating a message, set the maxSizeOfHeaders parameter if MaxReceivedMessageSize does not offer enough protection.

  • При создании кодировщика всегда настраивайте соответствующие квоты, например MaxSessionSize и MaxBufferSize.When creating an encoder, always configure the relevant quotas, such as MaxSessionSize and MaxBufferSize.

  • Если используется фильтр сообщений XPath, задавайте NodeQuota , чтобы ограничить число XML-узлов, посещаемых фильтром.When using an XPath message filter, set the NodeQuota to limit the amount of XML nodes the filter visits. Не используйте выражения XPath, которые могут потребовать длительного времени для вычисления без посещения большого числа узлов.Do not use XPath expressions that could take a long time to compute without visiting many nodes.

  • В целом при создании любого компонента, принимающего квоту, следует понимать последствия нарушения безопасности и задавать для него безопасное значение.In general, when using any component that accepts a quota, understand its security implications and set it to a safe value.

См. такжеSee also