
[CVE-2022-22980] Spring Data MongoDB SpEL инъекция выражений
[CVE-2022-22980] Внедрение SpEL-выражений в Spring Data MongoDB
MongoDB — это документо-ориентированная NoSQL-база данных, отличающаяся масштабируемостью и гибкостью и используемая для хранения больших объёмов данных. Вместо таблиц и строк, как в традиционных реляционных базах данных, MongoDB использует коллекции и документы. Документы состоят из пар «ключ-значение», которые являются базовой единицей данных в MongoDB.
Spring Data for MongoDB — часть зонтичного проекта Spring Data, который предназначен для предоставления знакомой и согласованной модели программирования на основе Spring для новых хранилищ данных с сохранением специфических для хранилища функций и возможностей. Проект Spring Data MongoDB обеспечивает интеграцию с документо-ориентированной базой данных MongoDB. Ключевыми функциональными областями Spring Data MongoDB являются модель, ориентированная на POJO, для взаимодействия с DBCollection MongoDB и простое создание репозитория в стиле уровня доступа к данным.
20 июня 2022 года VMware опубликовала на своём официальном сайте рекомендации по безопасности, касающиеся уязвимости внедрения SpEL-выражений (приводящей к удалённому выполнению кода), затрагивающей Spring Data MongoDB. Подробную информацию об уязвимости CVE-2022-22980 вы можете найти ниже.
Уязвимость
Приложение Spring Data MongoDB уязвимо к внедрению SpEL при использовании методов запросов, аннотированных @Query или @Aggregation, с SpEL-выражениями, содержащими заполнители параметров запроса для привязки значений, если входные данные не санитизируются. Кроме того, конфигурации, которые предоставляют методы репозитория без привлечения дополнительного кода приложения (например, Spring Data REST), также уязвимы.
В частности, приложение уязвимо, когда выполняются все следующие условия:
@Query или @Aggregation, использующими SpEL (Spring Expression Language), и ссылки на входные параметры (?0, ?1, …) применяются внутри SpEL-выраженияПриложение не уязвимо, если выполняется любое из следующих условий:
QueryMethodEvaluationContextProvider, который ограничивает использование SpELЗатронутые версии
Spring Data MongoDB 3.4.0, 3.3.0–3.3.4 и более старые версии подвержены уязвимости CVE-2022-22980 Spring Data MongoDB SpEL Expression Injection.
Статус
Выпущены Spring Data MongoDB 3.4.1 и 3.3.5, содержащие исправления.
Смягчение уязвимости и рекомендуемые обходные пути
Предпочтительное решение — обновление до Spring Data MongoDB 3.4.1 и 3.3.5 или новее. Если вы это сделали, дополнительные обходные пути не нужны. Однако некоторые могут оказаться в ситуации, когда быстрое обновление невозможно. По этой причине команда Spring предоставила несколько обходных путей ниже.
Использование синтаксиса массивов: если приложению требуются динамические SpEL-выражения, управляемые пользовательским вводом, перепишите объявления запросов или агрегаций, чтобы использовать ссылки на параметры ([0] вместо ?0) внутри выраженияРеализация пользовательского метода репозитория: замена SpEL-выражения реализацией пользовательского метода репозитория — жизнеспособный обходной путь для сборки динамического запроса в коде приложения. Дополнительные сведения см. в справочной документации по настройке репозиториев.Анализ исправления: проблема на GitHub и связанные коммиты
Проблема GitHub, связанная с уязвимостью внедрения SpEL, доступна по адресу github.com/spring-projects/spring-data-mongodb/issues/4089.
С помощью двух приведённых ниже коммитов соответствующая уязвимость была исправлена.
Вместе с этими коммитами был добавлен класс spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/EvaluationContextExpressionEvaluator.java.
class EvaluationContextExpressionEvaluator implements SpELExpressionEvaluator {
ValueProvider valueProvider;
ExpressionParser expressionParser;
Supplier<EvaluationContext> evaluationContext;
public EvaluationContextExpressionEvaluator(ValueProvider valueProvider, ExpressionParser expressionParser,
Supplier<EvaluationContext> evaluationContext) {
this.valueProvider = valueProvider;
this.expressionParser = expressionParser;
this.evaluationContext = evaluationContext;
}
@Nullable
@Override
public <T> T evaluate(String expression) {
return evaluateExpression(expression, Collections.emptyMap());
}
public EvaluationContext getEvaluationContext(String expressionString) {
return evaluationContext != null ? evaluationContext.get() : new StandardEvaluationContext();
}
public SpelExpression getParsedExpression(String expressionString) {
return (SpelExpression) (expressionParser != null ? expressionParser : new SpelExpressionParser())
.parseExpression(expressionString);
}
public <T> T evaluateExpression(String expressionString, Map<String, Object> variables) {
SpelExpression expression = getParsedExpression(expressionString);
EvaluationContext ctx = getEvaluationContext(expressionString);
variables.entrySet().forEach(entry -> ctx.setVariable(entry.getKey(), entry.getValue()));
Object result = expression.getValue(ctx, Object.class);
return (T) result;
}
}

Класс spring-projects/spring-data-mongodb/blob/main/spring-data-mongodb/src/main/java/org/springframework/data/mongodb/util/json/ParameterBindingContext.java также был изменён следующим образом: