SAX2 Security

 

This topic describes security issues associated with MSXML SAX2. In addition, it provides some guidance for mitigating security exposure.

MSXML 6.0 introduces several new security-oriented features. Defaults were changed for certain properties, which makes MSXML 6.0 more secure by default. For example, DTD processing is turned off by default and inline schemas are prohibited by default. We recommend that existing applications move to MSXML 6.0. All new applications should use MSXML 6.0.

Security Issues

The following sections describe important SAX2 security issues. They are not listed in any significant order. You should become familiar with all the issues discussed, and address them in your applications.

There is overlap between this topic and the DOM Security topic. This is because the issues discussed have more to do with XML in general than with the specific implementation (DOM or SAX).

Properties and Features that Have Security Implications

The following list provides a short description of the security implications associated with certain SAX2 properties and features. This list might not be complete.

Property/Feature Default value Security implication
max-element-depth 0 in 3.0; 256 in 6.0. A document that has an excessive depth of hierarchy can cause a denial of service (DoS) attack.
max-xml-size 0 If a malicious user submits or uploads a very large XML document, it can cause MSXML to consume excessive system resources. This might result in a denial of service attack.
prohibit-dtd false in 3.0; true in 6.0. Entities in DTDs are not secure. A malicious user can submit an XML document that contains a DTD that causes a denial of service attack.
use-schema-location Feature false. Various denial of service attacks are associated with compiling and validating XML schemas. Users should not accept schemas from untrusted sources if denial of service is a concern.
use-inline-schema Feature false. If you accept documents from an untrusted source, you cannot prevent denial of service attacks if you allow inline schemas. Like other schemas from untrusted sources, inline schemas allow an untrusted user to change the logic that is used for validating data.

DTDs Are Not Secure

Entities in DTDs are inherently not secure. It is possible for a malicious XML document that contains a DTD to cause the parser to use all memory and CPU time, causing a denial of service attack. Therefore, DTD processing is turned off by default. You should not accept DTDs from untrusted sources.

DTDs are enabled in MSXML 3.0. DTDs are disabled by default in MSXML 6.0 (the prohibit-dtd feature is set to true). If you know that all documents referencing DTDs come from secure sites, then you can allow DTD processing by setting the prohibit-dtd feature to false. The following is the C++ code to allow/prohibit the use of DTDs:

To allow DTDs:

ISAXXMLReader*pReader = NULL;  
HRESULT hr = CoCreateInstance(uuidof(MSXML2::SAXXMLReader60), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pReader));  
if (SUCCEEDED(hr))   
hr = pReader->putFeature(L"prohibit-dtd", VARIANT_FALSE);  

To disallow DTDs:

ISAXXMLReader*pReader = NULL;  
HRESULT hr = CoCreateInstance(__uuidof(MSXML2::SAXXMLReader60), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pReader));  
if (SUCCEEDED(hr))   
hr = pReader->putFeature(L"prohibit-dtd", VARIANT_TRUE);  
  

The following is C++ code to allow DTDs:

ISAXXMLReader* pRdr = NULL;  
  
HRESULT hr = CoCreateInstance(  
  __uuidof(MSXML2::SAXXMLReader60),   
  NULL,   
  CLSCTX_ALL,   
  __uuidof(ISAXXMLReader),   
  (void **)&pRdr);  
  
if(!FAILED(hr))   
{  
  MyContent * pMc = new MyContent();  
  hr = pRdr->putContentHandler(pMc);  
  
}  
if (!FAILED(hr))  
  hr = pRdr->putFeature(L"prohibit-dtd", VARIANT_FALSE);  
  

If you attempt to load an XML document that contains a DTD while this feature is set to true, you will receive an error. In MSXML 6.0, the error is "DTD is prohibited." Other versions of MSXML may report a different error.

If you must use MSXML 3.0, and you must accept documents from untrusted sources, you can disable entities. This will help prevent denial of service attacks.

Schemas Should Not Be Loaded from Untrusted Sources

There are a number of denial of service attacks associated with compiling and validating XML schemas. Users should not accept schemas from untrusted sources if denial of service is a concern.

In MSXML 6.0, external schemas are not processed by default; they must be explicitly enabled by the developer (the default value for use-schema-location is false). If you are using MSXML 6.0 and all of your XML documents come from a secure site, and you want to allow external schemas, you can do so by setting the feature use-schema-location to true. For more information about these features, see SAX Reader Features.

To allow external schemas in MSXML 6.0:

ISAXXMLReader*pReader = NULL;  
HRESULT hr = CoCreateInstance(uuidof(MSXML2::SAXXMLReader60), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pReader));  
if (SUCCEEDED(hr))   
hr = pReader->putFeature(L"use-schema-location", VARIANT_FALSE);  
  

Inline Schemas Are Not Secure

The following security issue is similar to the issue of accepting schemas from untrusted sources. If you accept documents from an untrusted source, it is not possible to prevent denial of service attacks when allowing inline schemas.

Inline schemas are not supported in MSXML 3.0. The default value for MSXML 6.0 is false. If you are using MSXML 6.0 and you know that all of your documents come from a secure source, you can allow inline schemas by setting the use-inline-schema and schema-validation features to true. For more information about these features, see SAX Reader Features.

To allow inline schemas and schema validation in MSXML 6.0:

ISAXXMLReader*pReader = NULL;  
HRESULT hr = CoCreateInstance(uuidof(MSXML2::SAXXMLReader60), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pReader));  
if (SUCCEEDED(hr))   
hr = pReader->putFeature(L"use-inline-schema", VARIANT_TRUE);  
if (SUCCEEDED(hr))  
hr = pReader->putFeature(L"schema-validation", VARIANT_TRUE);  
  

Prevention of Cross-Domain and Cross-Zone Attacks

If you accept documents from insecure sites, and you want to load external documents (using xsi:schemaLocation in the case of instance documents and xs:import and xs:include in the case of schema documents), you should set the secureBaseURL property in Visual Basic. If you are using C++, you should call the putSecureBaseURL method. The secureBaseURL determines the permissions of accessing externals within the document. This will mitigate cross-zone or cross-domain attacks.

For example, if an XML document is uploaded to your application, your application has use-schema-location set to true, and you do not have the secureBaseURL property set, then that document could attempt to load or include a schema from your local machine. This type of attack may result in denial of service, information disclosure from the protected resource, or data tampering.

Avoid Excessive Buffer Allocation

If a malicious user submits or uploads a very large XML document, it could cause MSXML to consume excessive system resources. This would be a denial of service attack. To prevent this, you can set the property max-xml-size (SAX Reader Properties) to a reasonable value for the application's expected operations. This will limit the size of uploaded XML documents. A zero (0) value means no limits. A non-zero value specifies the maximum size, in multiples of 1024 characters. The default value of max-xml-size is unlimited.

For example, if you know that the maximum expected size of your XML documents coming from an untrusted source will be less than 50K bytes, set max-xml-size to 100. This will not encumber your processing of XML documents, and at the same time it will mitigate denial of service threats from documents that would consume large amounts of memory.

The following C++ code sets max-xml-size:

ISAXXMLReader*pReader = NULL;  
HRESULT hr = CoCreateInstance(uuidof(MSXML2::SAXXMLReader60), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pReader));  
if (SUCCEEDED(hr))   
hr = pReader->putFeature(L"max-xml-size", 100);  

When setting the max-xml-size, you should be aware of the memory available and the memory required by other components. This property should never be larger than the total amount of memory available to the MSXML process.

Limit the Depth of the XML Hierarchy

One possible denial of service attack is when a document is submitted that has excessive nesting of elements. If you are concerned about denial of service, you should limit the depth of the hierarchy. Failure to limit the depth of hierarchy leaves you open to the exploit where a relatively small XML document can cause a denial of service.

To prevent this, you can set the property max-element-depth (SAX Reader Properties) to a reasonable value for the application's expected operations. A zero (0) value means no limits. A non-zero value specifies the maximum depth. The default value for this property is 256. If you are concerned about denial of service, you should set this property to a value that allows you to load your documents yet limits depth to a reasonable level. It is not recommended that this property be set to 0, which removes the limit.

The following C++ code sets max-element-depth:

ISAXXMLReader*pReader = NULL;  
HRESULT hr = CoCreateInstance(uuidof(MSXML2::SAXXMLReader60), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pReader));  
if (SUCCEEDED(hr))   
hr = pReader->putFeature(L"max-element-depth", 100);  

The max-element-depth property is supported for MSXML 6.0.

Error Messages May Reveal Data

Certain types of threats require that you program your application in certain ways. For example, the description of an error may reveal data such as the data being transformed. Errors may also reveal file names. Error messages should not be exposed to callers that are not trusted. You should catch all errors and report errors with your own custom error messages.

See Also

MSXML Security Overview