flawopen.com/XXE/Lectores XML de .NET
¿Es XmlReader seguro frente a XXE en .NET?
Piensa en un DTD como un permiso para que el parser busque documentos indicados en el XML. XmlReader.Create rechaza DTD por defecto, así que un documento no confiable no puede usar esa vía a menos que la aplicación la habilite. Las API heredadas y el framework de destino también importan: prohíbe los DTD explícitamente y desactiva la resolución externa en el límite de análisis.
// Lector heredado directo: puede habilitarse el análisis DTD // y un resolver externo puede buscar recursos referenciados. var legacy = new XmlTextReader(stream) { DtdProcessing = DtdProcessing.Parse, XmlResolver = new XmlUrlResolver() }; while (legacy.Read()) { } // Habilitar DTD explícitamente para XML no confiable es arriesgado: var unsafeSettings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Parse, XmlResolver = new XmlUrlResolver() }; using var reader = XmlReader.Create(stream, unsafeSettings);
var settings = new XmlReaderSettings {
// Rechaza cualquier documento que contenga un DTD.
DtdProcessing = DtdProcessing.Prohibit,
// Defensa en profundidad: no busques recursos externos.
XmlResolver = null,
// Ajusta los límites al contenido legítimo de la aplicación.
MaxCharactersInDocument = 1_000_000,
MaxCharactersFromEntities = 1_024,
};
using var reader = XmlReader.Create(stream, settings);
var doc = new XmlDocument { XmlResolver = null };
doc.Load(reader);
¿Qué API XML y versión de .NET utilizas?
.NET has several XML APIs whose defaults have differed, and whose defaults have also changed across framework versions. The practical summary:
- ✓XmlReader.Create con ajustes predeterminados — DtdProcessing.Prohibit es el valor predeterminado. Establécelo explícitamente al recibir datos no confiables para impedir que un cambio posterior habilite DTD sin darte cuenta.
- ✓XmlReaderSettings.XmlResolver — .NET Framework 4.5.2 cambió el valor predeterminado a null; versiones anteriores podían usar XmlUrlResolver. Asigna null explícitamente y comprueba la opción de compatibilidad EnableLegacyXmlSettings.
- ✓XmlTextReader — el uso directo de esta API heredada tiene otros valores predeterminados y puede analizar DTD. Prefiere XmlReader.Create con ajustes explícitos; nunca asocies un resolver de red o archivos a XML no confiable.
- ✓XmlDocument y LINQ to XML — el comportamiento depende de cómo se carga el documento y del framework de destino. Pásales un XmlReader reforzado y establece cualquier resolver disponible en null.
El cambio de .NET Framework 4.5.2 estableció XmlReaderSettings.XmlResolver en null e inicializó MaxCharactersFromEntities en 10 millones; no hizo equivalentes todas las API XML ni todas las configuraciones. Una opción de compatibilidad puede restaurar los valores antiguos. Configura expresamente el parser, limita el tamaño del documento y comprueba la versión y la configuración reales de ejecución.
Preguntas frecuentes
Sí. XmlReaderSettings.DtdProcessing tiene el valor predeterminado Prohibit y lanza una excepción al encontrar un DTD. Aun así, establécelo explícitamente y usa XmlResolver = null como defensa en profundidad.
Por seguridad, XmlReaderSettings.XmlResolver pasó a tener el valor predeterminado null, y MaxCharactersFromEntities se inicializa en 10 millones. La opción EnableLegacyXmlSettings puede restaurar el comportamiento anterior; comprueba la configuración desplegada, no solo el framework de destino.
Puede afectarlo. Estos formatos contienen XML, pero el efecto depende del parser y de sus ajustes. Haz que cada entrada XML no confiable use un lector reforzado, limita el tamaño de entrada y consulta también las recomendaciones de seguridad de la biblioteca del formato.
Fuentes y referencias
- Microsoft Learn — XmlReaderSettings y consideraciones de seguridad
- Microsoft Learn — cambios de análisis XML en .NET Framework 4.5.2
- Microsoft Learn — XmlReader.Create y resolución
- Microsoft Learn — XmlTextReader.XmlResolver
- OWASP — prevención de XXE
- CWE-611 — referencia a entidad externa XML
- Valores predeterminados XXE de DocumentBuilderFactory en Java