Limit SpEL expression length

This commit enforces a limit of the maximum size of a single SpEL
expression.

Closes gh-30325
This commit is contained in:
Sam Brannen 2023-04-07 18:13:02 +02:00 committed by Brian Clozel
parent bc1511d667
commit b73f5fcac2
3 changed files with 36 additions and 3 deletions

View File

@ -268,15 +268,19 @@ public enum SpelMessage {
/** @since 5.2.23 */
MAX_REPEATED_TEXT_SIZE_EXCEEDED(Kind.ERROR, 1076,
"Repeated text results in too many characters, exceeding the threshold of ''{0}''"),
"Repeated text is too long, exceeding the threshold of ''{0}'' characters"),
/** @since 5.2.23 */
MAX_REGEX_LENGTH_EXCEEDED(Kind.ERROR, 1077,
"Regular expression contains too many characters, exceeding the threshold of ''{0}''"),
"Regular expression is too long, exceeding the threshold of ''{0}'' characters"),
/** @since 5.2.24 */
MAX_CONCATENATED_STRING_LENGTH_EXCEEDED(Kind.ERROR, 1078,
"Concatenated string is too long, exceeding the threshold of ''{0}'' characters");
"Concatenated string is too long, exceeding the threshold of ''{0}'' characters"),
/** @since 5.2.24 */
MAX_EXPRESSION_LENGTH_EXCEEDED(Kind.ERROR, 1079,
"SpEL expression is too long, exceeding the threshold of ''{0}'' characters");
private final Kind kind;

View File

@ -29,6 +29,7 @@ import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateAwareExpressionParser;
import org.springframework.expression.spel.InternalParseException;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.SpelParseException;
import org.springframework.expression.spel.SpelParserConfiguration;
@ -92,6 +93,12 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
private static final Pattern VALID_QUALIFIED_ID_PATTERN = Pattern.compile("[\\p{L}\\p{N}_$]+");
/**
* Maximum length permitted for a SpEL expression.
* @since 5.2.24
*/
private static final int MAX_EXPRESSION_LENGTH = 10_000;
private final SpelParserConfiguration configuration;
@ -127,6 +134,8 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
protected SpelExpression doParseExpression(String expressionString, @Nullable ParserContext context)
throws ParseException {
checkExpressionLength(expressionString);
try {
this.expressionString = expressionString;
Tokenizer tokenizer = new Tokenizer(expressionString);
@ -148,6 +157,12 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
}
}
private void checkExpressionLength(String string) {
if (string.length() > MAX_EXPRESSION_LENGTH) {
throw new SpelEvaluationException(SpelMessage.MAX_EXPRESSION_LENGTH_EXCEEDED, MAX_EXPRESSION_LENGTH);
}
}
// expression
// : logicalOrExpression
// ( (ASSIGN^ logicalOrExpression)

View File

@ -60,6 +60,20 @@ class EvaluationTests extends AbstractExpressionTests {
@Nested
class MiscellaneousTests {
@Test
void expressionLength() {
String expression = "'X' + '%s'".formatted(" ".repeat(9_992));
assertThat(expression).hasSize(10_000);
Expression expr = parser.parseExpression(expression);
String result = expr.getValue(context, String.class);
assertThat(result).hasSize(9_993);
assertThat(result.trim()).isEqualTo("X");
expression = "'X' + '%s'".formatted(" ".repeat(9_993));
assertThat(expression).hasSize(10_001);
evaluateAndCheckError(expression, String.class, SpelMessage.MAX_EXPRESSION_LENGTH_EXCEEDED);
}
@Test
void createListsOnAttemptToIndexNull01() throws EvaluationException, ParseException {
ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));