Limit SpEL expression length

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

Closes gh-30329
This commit is contained in:
Sam Brannen
2023-04-07 18:13:02 +02:00
committed by Brian Clozel
parent 86457464d7
commit ebc8265428
3 changed files with 45 additions and 11 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 = String.format("'X' + '%s'", 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 = String.format("'X' + '%s'", 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));
@@ -492,14 +506,6 @@ class EvaluationTests extends AbstractExpressionTests {
evaluateAndCheckError("'abc' matches '" + pattern + "'", Boolean.class, SpelMessage.MAX_REGEX_LENGTH_EXCEEDED);
}
private String repeat(String str, int count) {
String result = "";
for (int i = 0; i < count; i++) {
result += str;
}
return result;
}
}
@Nested
@@ -1474,6 +1480,15 @@ class EvaluationTests extends AbstractExpressionTests {
}
private static String repeat(String str, int count) {
String result = "";
for (int i = 0; i < count; i++) {
result += str;
}
return result;
}
@SuppressWarnings("rawtypes")
static class TestClass {