using System; using System.IO; using System.Text; using System.Xml; using System.Xml.Serialization; namespace Wayne.Lib { /// /// A util class to create and classes resistant to XXE attacks.> /// /// /// https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet /// public static class Xml { #region XmlDocument Constructors /// /// Initializes a new instance of the class. /// public static XmlDocument Document() { return FixDocument(new XmlDocument()); } /// /// Initializes a new instance of the class with the specified . /// public static XmlDocument Document(XmlNameTable nt) { return FixDocument(new XmlDocument(nt)); } #endregion #region XmlReader Constructors /// /// Replace Create method. Creates a new instance using the specified with default settings. /// public static XmlReader Reader(Stream input) { return XmlReader.Create(input, FixSettings()); } /// /// Replace Create method. Creates a new instance using the specified and . /// public static XmlReader Reader(Stream input, XmlReaderSettings settings) { return XmlReader.Create(input, FixSettings(settings)); } /// /// Replace Create method. Creates a new instance by using the specified . /// public static XmlReader Reader(TextReader input) { return XmlReader.Create(input, FixSettings()); } /// /// Replace Create method. Creates a new instance by using the specified and . /// public static XmlReader Reader(TextReader input, XmlReaderSettings settings) { return XmlReader.Create(input, FixSettings(settings)); } #endregion #region GetEncoding /// /// Gets the encoded of the undeling xml data. Uses to read the data. /// public static string GetEncodedString(byte[] data, int offset, int length) { string ret = null; System.Text.Encoding encoding = GetEncoding(data, offset, length); if (encoding != null && encoding.CodePage != 0) { ret = encoding.GetString(data, offset, length); } else { ret = System.Text.Encoding.UTF8.GetString(data, offset, length); } return ret; } #endregion #region Serialization /// /// Serializes a class instance to . /// public static string Serialize(T instance) where T : class { var xmlWriterSettings = new XmlWriterSettings { Encoding = new UTF8Encoding(false) }; using (var stream = new MemoryStream()) using (var writer = XmlWriter.Create(stream, xmlWriterSettings)) { var serializer = new XmlSerializer(typeof(T)); serializer.Serialize(writer, instance); return System.Text.Encoding.UTF8.GetString(stream.ToArray(), 0, (int)stream.Length); } } /// /// Deserialize a xml . /// public static T Deserialize(string xml) where T : class { using (var reader = new StringReader(xml)) { var serializer = new XmlSerializer(typeof(T)); return serializer.Deserialize(reader) as T; } } /// /// Deserializes XmlDocument object to Serializable object of type T. /// /// Serializable object type as output type. /// XmlDocument object to be deserialized. /// Deserialized serializable object of type T. public static T Deserialize(XmlDocument document) where T : class { using (var reader = new XmlNodeReader(document)) { var serializer = new XmlSerializer(typeof(T)); return serializer.Deserialize(reader) as T; } } #endregion #region Implementation private static System.Text.Encoding GetEncoding(byte[] data, int offset, int length) { System.Text.Encoding encoding = null; using (var stream = new MemoryStream(data, offset, length)) { using (var reader = FixTextReader(new XmlTextReader(stream))) { reader.Read(); encoding = reader.Encoding; } } return encoding; } private static XmlDocument FixDocument(XmlDocument document) { document.XmlResolver = null; // Setting XmlResolver to NULL disables DTDs - Its NOT null by default. return document; } private static XmlTextReader FixTextReader(XmlTextReader reader) { #if WindowsCE || OldFramework //Dtd processing is not supprted in .Net Compact Framework #else reader.DtdProcessing = DtdProcessing.Prohibit; // Needed because the default is Parse!! #endif return reader; } private static XmlReaderSettings FixSettings() { return FixSettings(null); } private static XmlReaderSettings FixSettings(XmlReaderSettings settings) { if (settings == null) { settings = new XmlReaderSettings(); } #if WindowsCE || OldFramework //Dtd processing is not supprted in .Net Compact Framework #else settings.DtdProcessing = DtdProcessing.Prohibit; // Needed because the default is Parse!! #endif return settings; } #endregion } }