Limit string concatenation in SpEL expressions

This commit introduces support for limiting the maximum length of a
string resulting from the concatenation operator (+) in SpEL
expressions.

Closes gh-30331
This commit is contained in:
Sam Brannen
2023-04-07 17:02:09 +02:00
committed by Brian Clozel
parent be129dc171
commit 86457464d7
3 changed files with 99 additions and 17 deletions

View File

@@ -272,7 +272,11 @@ public enum SpelMessage {
/** @since 5.2.23 */
MAX_REGEX_LENGTH_EXCEEDED(Kind.ERROR, 1077,
"Regular expression contains too many characters, exceeding the threshold of ''{0}''");
"Regular expression contains too many characters, exceeding the threshold of ''{0}''"),
/** @since 5.2.24 */
MAX_CONCATENATED_STRING_LENGTH_EXCEEDED(Kind.ERROR, 1078,
"Concatenated string is too long, exceeding the threshold of ''{0}'' characters");
private final Kind kind;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -27,6 +27,8 @@ import org.springframework.expression.TypeConverter;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.CodeFlow;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.NumberUtils;
@@ -46,10 +48,18 @@ import org.springframework.util.NumberUtils;
* @author Juergen Hoeller
* @author Ivo Smid
* @author Giovanni Dall'Oglio Risso
* @author Sam Brannen
* @since 3.0
*/
public class OpPlus extends Operator {
/**
* Maximum number of characters permitted in a concatenated string.
* @since 5.2.24
*/
private static final int MAX_CONCATENATED_STRING_LENGTH = 100_000;
public OpPlus(int startPos, int endPos, SpelNodeImpl... operands) {
super("+", startPos, endPos, operands);
Assert.notEmpty(operands, "Operands must not be empty");
@@ -123,22 +133,45 @@ public class OpPlus extends Operator {
if (leftOperand instanceof String && rightOperand instanceof String) {
this.exitTypeDescriptor = "Ljava/lang/String";
return new TypedValue((String) leftOperand + rightOperand);
String leftString = (String) leftOperand;
String rightString = (String) rightOperand;
checkStringLength(leftString);
checkStringLength(rightString);
return concatenate(leftString, rightString);
}
if (leftOperand instanceof String) {
return new TypedValue(
leftOperand + (rightOperand == null ? "null" : convertTypedValueToString(operandTwoValue, state)));
String leftString = (String) leftOperand;
checkStringLength(leftString);
String rightString = (rightOperand == null ? "null" : convertTypedValueToString(operandTwoValue, state));
checkStringLength(rightString);
return concatenate(leftString, rightString);
}
if (rightOperand instanceof String) {
return new TypedValue(
(leftOperand == null ? "null" : convertTypedValueToString(operandOneValue, state)) + rightOperand);
String rightString = (String) rightOperand;
checkStringLength(rightString);
String leftString = (leftOperand == null ? "null" : convertTypedValueToString(operandOneValue, state));
checkStringLength(leftString);
return concatenate(leftString, rightString);
}
return state.operate(Operation.ADD, leftOperand, rightOperand);
}
private void checkStringLength(String string) {
if (string.length() > MAX_CONCATENATED_STRING_LENGTH) {
throw new SpelEvaluationException(getStartPosition(),
SpelMessage.MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, MAX_CONCATENATED_STRING_LENGTH);
}
}
private TypedValue concatenate(String leftString, String rightString) {
String result = leftString + rightString;
checkStringLength(result);
return new TypedValue(result);
}
@Override
public String toStringAST() {
if (this.children.length < 2) { // unary plus