Skip to content

Commit

Permalink
Limit SpEL expression length
Browse files Browse the repository at this point in the history
This commit enforces a limit of the maximum size of a single SpEL
expression.

Closes gh-30330
  • Loading branch information
sbrannen authored and bclozel committed Apr 13, 2023
1 parent cbbb287 commit 965a639
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -264,15 +264,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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -127,6 +134,8 @@ public InternalSpelExpressionParser(SpelParserConfiguration configuration) {
protected SpelExpression doParseExpression(String expressionString, @Nullable ParserContext context)
throws ParseException {

checkExpressionLength(expressionString);

try {
this.expressionString = expressionString;
Tokenizer tokenizer = new Tokenizer(expressionString);
Expand All @@ -148,6 +157,12 @@ protected SpelExpression doParseExpression(String expressionString, @Nullable Pa
}
}

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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,20 @@
*/
public class EvaluationTests extends AbstractExpressionTests {

@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
public void testCreateListsOnAttemptToIndexNull01() throws EvaluationException, ParseException {
ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
Expand Down Expand Up @@ -211,14 +225,6 @@ void matchesWithPatternLengthThreshold() {
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;
}

// mixing operators
@Test
public void testMixingOperators01() {
Expand Down Expand Up @@ -1373,6 +1379,15 @@ public List<Method> filter(List<Method> methods) {
}


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 {

Expand Down

0 comments on commit 965a639

Please sign in to comment.