V5312. OWASP. Possible XPath injection. Potentially tainted data is used in the XPath expression.
Анализатор обнаружил, что для формирования выражения на языке XPath используются непроверенные данные из внешнего источника. Это может стать причиной возникновения XPath-инъекции.
Уязвимости, связанные с инъекциями, относятся к категории A03:2021 – Injection списка OWASP Top 10 Application Security Risks.
Рассмотрим пример:
public class UserData {
HttpServletRequest request;
MessageDigest digest;
Document doc;
public void retrieveUserData() {
String user = request.getParameter("username");
String password = request.getParameter("password");
String passwordHash = Arrays.toString(
digest.digest(password.getBytes(StandardCharsets.UTF_8))
);
var xpath = XPathFactory.newInstance().newXPath();
String query = "//users/user[" +
"username/text() = '%s' and" +
"passwordHash/text() = '%s']" +
"/data/text()";
query = String.format(query, user, passwordHash);
try {
String result = xpath.evaluate(query, doc);
// ....
} catch (XPathExpressionException e) {
// ....
}
//....
}
}
В этом примере XPath-выражение используется для получения данных пользователя из XML-файла. Имя пользователя хранится "как есть", а пароль хранится в зашифрованном виде.
Злоумышленник может передать в качестве имени пользователя и пароля любые данные. Проверка будет скомпрометирована, если во входных данных передать выражение, которое сделает XPath-условие всегда истинным. Так как пароль хранится в зашифрованном виде, то внедрять опасное выражение нужно вместе с именем пользователя.
Для примера, пусть имя пользователя будет john
. Добавим к нему выражение такого вида:
' or ''='
Вместо пароля может быть введён любой набор символов. Тогда XPath-выражение будет иметь такой вид:
[
username/text()='john' or ''='' and
passwordHash/text() = '750084105bcbe9d2c89ba9b'
]
Теперь выражение содержит оператор or
. Рассмотрим, как оно вычисляется:
- Так как имя пользователя существует, выражение
username/text()='john'
является истинным. - В качестве пароля были введены случайные символы, поэтому выражение
passwordHash/text() = '750084105bcbe9d2c89ba9b'
является ложным. - Выражение ''='' всегда истинно.
- Приоритет оператора
and
выше, чемor
, поэтому происходит вычисление выражения''='' and passwordHash/text() = '750084105bcbe9d2c89ba9b'
. Результатом является ложь. - Последним выполняется оператор
or
. Выражениеusername/text()='john' or false
является истинным. Следовательно, всё условие является истинным.
Таким образом, результатом XPath-запроса будут данные пользователя 'john' независимо от того, правильный пароль был введён или нет. Это может привести к утечке данных.
Не следует использовать непроверенные внешние данные в XPath-выражениях. Для повышения безопасности стоит экранировать потенциально опасные символы во внешних данных. Примерами таких символов являются <
, >
и '
. Экранирование может быть произведено с помощью простого replaceAll
:
public class UserData {
HttpServletRequest request;
MessageDigest digest;
Document doc;
public void retrieveUserData() {
String user = request.getParameter("username")
.replaceAll("'", "&abos;");
String password = request.getParameter("password");
String passwordHash = Arrays.toString(
digest.digest(password.getBytes(StandardCharsets.UTF_8))
);
var xpath = XPathFactory.newInstance().newXPath();
String query = "//users/user[" +
"username/text() = '%s' and" +
"passwordHash/text() = '%s']" +
"/data/text()";
query = String.format(query, user, passwordHash);
try {
String result = xpath.evaluate(query, doc);
// ....
} catch (XPathExpressionException e) {
// ....
}
//....
}
}
Apache Commons Text также содержит класс утилит StringEscapeUtils
, двумя методами которого являются escapeXml10
и escapeXml11
. Эти методы позволят экранировать все необходимые символы.
Существуют другие возможности для предотвращения XPath-инъекций. Например, Oracle предлагает возможность реализации класса-резолвера. Его можно использовать в объектах класса XPath. Это позволяет определить свои собственные переменные и функции внутри XPath-выражения, которые будут обработаны резолвером.