Анализатор обнаружил, что для формирования выражения на языке XPath используются непроверенные данные из внешнего источника. Это может стать причиной возникновения XPath-инъекции.
Уязвимости, связанные с инъекциями, относятся к категории A03:2021 – Injection списка OWASP Top 10 Application Security Risks.
Рассмотрим пример:
class UserData { HttpRequest request; XPathNavigator navigator; void RetrieveUserData() { string username = request.Form["username"]; string password = request.Form["password"]; string hashedPassword = Hash(password); string query = $@"//users/user[ username/text() = '{username}' and passwordHash/text() = '{hashedPassword}'] /data/text()"; object res = navigator.Evaluate(query); .... } }
В этом примере XPath-выражение используется для получения данных пользователя из XML-файла. Имя пользователя хранится "как есть", а пароль хранится в зашифрованном виде.
Злоумышленник может передать в качестве имени пользователя и пароля любые данные. Проверка будет скомпрометирована, если во входных данных передать выражение, которое сделает XPath-условие всегда истинным. Так как пароль хранится в зашифрованном виде, то внедрять опасное выражение нужно вместе с именем пользователя.
Для примера пусть имя пользователя будет 'john'. Добавим к нему выражение такого вида:
' or ''='
Вместо пароля может быть введён любой набор символов. Тогда XPath-выражение будет иметь такой вид:
[ username/text()='john' or ''='' and passwordHash/text() = '750084105bcbe9d2c89ba9b' ]
Теперь выражение содержит оператор 'or'. Рассмотрим, как оно вычисляется:
Таким образом, результатом XPath-запроса будут данные пользователя 'john' независимо от того, правильный пароль был введён или нет. Это может привести к утечке данных.
Не следует использовать непроверенные внешние данные в XPath-выражениях. Для повышения безопасности стоит экранировать потенциально опасные символы во внешних данных. Примерами таких символов являются "<", ">" и "'". Экранирование может быть произведено с помощью метода 'SecurityElement.Escape':
class UserData { HttpRequest request; XPathNavigator navigator; void RetrieveUserData() { string username = request.Form["username"]; string password = request.Form["password"]; username = SecurityElement.Escape(username); string hashedPassword = Hash(password); string query = $@"//users/user[ username/text()= '{username}' and passwordHash/text() ='{hashedPassword}'] /data/text()"; object res = navigator.Evaluate(query); .... } }
Существуют другие возможности для предотвращения XPath-инъекций. Например, Microsoft предлагает возможность реализации класса-резолвера. Его можно использовать в методах класса 'XPathNavigator', которые принимают строку XPath-выражения и объект, реализующий интерфейс 'IXmlNamespaceResolver'.
Это позволяет определить свои собственные переменные и функции внутри XPath-выражения, которые будут обработаны резолвером. Само по себе это не является решением проблемы XPath-инъекции, но определение своиx переменных позволяет использовать подход, похожий на параметризацию SQL-запросов.
Также анализатор считает источниками небезопасных данных параметры методов, доступных из других сборок. Более подробно эта тема раскрыта в заметке "Почему важно проверять значения параметров общедоступных методов". Рассмотрим пример:
public class UserData { XPathNavigator navigator; public object RetrieveUserData(string username, string password) { string hashedPassword = Hash(password); string query = $@"//users/user[ username/text()= '{username}' and passwordHash/text() = '{hashedPassword}'] /data/text()"; return EvaluateXpath(query); } private object EvaluateXpath(string xpath) { object res = navigator.Evaluate(xpath); .... } }
В этом примере метод 'RetrieveUserData' доступен из других сборок. Параметры этого метода 'username' и 'password' не проверяются перед внедрением в XPath-запрос. Полученное выражение в переменной 'query' передаётся в метод 'EvaluateXpath', где используется без проверки. В таком случае анализатор выдаст предупреждение с низким уровнем достоверности.
Данная диагностика классифицируется как:
|