Как предотвратить атаку XXE (XmlDocument в .net)
У нас был аудит безопасности на нашем коде, и они отметили, что наш код уязвим для атаки внешнего окружения (XXE). Я использую следующий код -
string OurOutputXMLString=
"<ce><input><transaction><length>00000</length><tran_type>Login</tran_type></transaction><user><user_id>ce_userid</user_id><subscriber_name>ce_subscribername</subscriber_name><subscriber_id>ce_subscriberid</subscriber_id><group_id>ce_groupid</group_id><permissions></permissions></user><consumer><login_details><username>UnitTester9</username><password>pDhE5AsKBHw85Sqgg6qdKQ==</password><pin>tOlkiae9epM=</pin></login_details></consumer></input></ce>"
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(OurOutputXMLString);
В отчете аудита говорится, что его отказ, поскольку XML-объект может содержать URL-адреса, которые могут разрешаться вне предполагаемого contronl. Обработчик сущности XML попытается разрешить и получить внешние ссылки. Если XML файл с контролируемым атакующем может быть отправлен на одну из этих функций, злоумышленник может получить доступ к информации о внутренней сети, локальной файловой системе или других конфиденциальных данных.
Чтобы этого избежать, я написал следующий код, но он не работает.
MemoryStream stream =
new MemoryStream(System.Text.Encoding.Default.GetBytes(OurOutputXMLString));
XmlReaderSettings settings = new XmlReaderSettings();
settings.DtdProcessing = DtdProcessing.Prohibit;
settings.MaxCharactersFromEntities = 6000;
XmlReader reader = XmlReader.Create(stream, settings);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(reader);
но я вижу здесь, что у читателя нет никакой ценности для загрузки в xmlDoc (XmlDocument).
Может ли кто-нибудь помочь, где я упускаю вещи?
Любая помощь приветствуется!
Ответы
Ответ 1
Внешние ресурсы разрешаются с помощью XmlResolver
, предоставляемого через свойство XmlDocument.XmlResolver
. Если ваши XML-документы ** не должны содержать никакого внешнего ресурса ** (например, DTD или схемы), просто установите это свойство как null
:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.XmlResolver = null;
xmlDoc.LoadXml(OurOutputXMLString);
Если вы хотите отфильтровать, откуда эти URL-адреса (например, разрешить только определенные домены), просто получить свой собственный класс из XmlUrlResolver
и переопределить метод ResolveUri()
. Там вы можете проверить, что такое URL и дезинфицировать его (например, вы можете разрешать только URL-адреса в своей локальной сети или из надежных источников).
Например:
class CustomUrlResovler : XmlUrlResolver
{
public override Uri ResolveUri(Uri baseUri, string relativeUri)
{
Uri uri = new Uri(baseUri, relativeUri);
if (IsUnsafeHost(uri.Host))
return null;
return base.ResolveUri(baseUri, relativeUri);
}
private bool IsUnsafeHost(string host)
{
return false;
}
}
Где IsUnsafeHost()
- это настраиваемая функция, которая проверяет, разрешен ли данный хост или нет. См. этот пост здесь, на SO за несколько идей. Просто верните null
из ResolveUri()
, чтобы сохранить код от такого рода атак. Если разрешен URI, вы можете просто вернуть реализацию по умолчанию XmlUrlResolver.ResolveUri()
.
Чтобы использовать его:
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.XmlResolver = new CustomUrlResolver();
xmlDoc.LoadXml(OurOutputXMLString);
Для получения более подробной информации о том, как разрешены внешние ресурсы XML, просто прочитайте Разрешение внешних ресурсов в MS Docs. Если ваш код более сложный, чем этот пример, вы должны обязательно прочитать Раздел замечаний для XmlDocument.XmlResolver.
Ответ 2
Итак, лучше использовать
new XmlDocument { XmlResolver = null };
Интересно, что из .net 4.5.2 и 4.6, по умолчанию распознаватель ведет себя по-разному и не использует XmlUrlResolver upfront неявно для разрешения любых URL-адресов или местоположений, как я видел.
//In pre 4.5.2 it is a security issue.
//In 4.5.2 it will not resolve any more the url references in dtd and such,
//Still better to avoid the below since it will trigger security warnings.
new XmlDocument();