mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Protect against deeply nested JSON lists
Update `BasicJsonParser` to protect against deeply nested JSON lists in the same way as Jackson. Fixes gh-31868
This commit is contained in:
parent
24c4ba3b53
commit
6966ebd2a3
@ -37,6 +37,8 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
public class BasicJsonParser extends AbstractJsonParser {
|
||||
|
||||
private static final int MAX_DEPTH = 1000;
|
||||
|
||||
@Override
|
||||
public Map<String, Object> parseMap(String json) {
|
||||
return tryParse(() -> parseMap(json, this::parseMapInternal), Exception.class);
|
||||
@ -44,21 +46,24 @@ public class BasicJsonParser extends AbstractJsonParser {
|
||||
|
||||
@Override
|
||||
public List<Object> parseList(String json) {
|
||||
return tryParse(() -> parseList(json, this::parseListInternal), Exception.class);
|
||||
return tryParse(() -> parseList(json, (jsonToParse) -> parseListInternal(0, jsonToParse)), Exception.class);
|
||||
}
|
||||
|
||||
private List<Object> parseListInternal(String json) {
|
||||
private List<Object> parseListInternal(int nesting, String json) {
|
||||
List<Object> list = new ArrayList<>();
|
||||
json = trimLeadingCharacter(trimTrailingCharacter(json, ']'), '[').trim();
|
||||
for (String value : tokenize(json)) {
|
||||
list.add(parseInternal(value));
|
||||
list.add(parseInternal(nesting + 1, value));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private Object parseInternal(String json) {
|
||||
private Object parseInternal(int nesting, String json) {
|
||||
if (nesting > MAX_DEPTH) {
|
||||
throw new IllegalStateException("JSON is too deeply nested");
|
||||
}
|
||||
if (json.startsWith("[")) {
|
||||
return parseListInternal(json);
|
||||
return parseListInternal(nesting + 1, json);
|
||||
}
|
||||
if (json.startsWith("{")) {
|
||||
return parseMapInternal(json);
|
||||
@ -101,7 +106,7 @@ public class BasicJsonParser extends AbstractJsonParser {
|
||||
for (String pair : tokenize(json)) {
|
||||
String[] values = StringUtils.trimArrayElements(StringUtils.split(pair, ":"));
|
||||
String key = trimLeadingCharacter(trimTrailingCharacter(values[0], '"'), '"');
|
||||
Object value = parseInternal(values[1]);
|
||||
Object value = parseInternal(0, values[1]);
|
||||
map.put(key, value);
|
||||
}
|
||||
return map;
|
||||
|
@ -16,11 +16,15 @@
|
||||
|
||||
package org.springframework.boot.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.util.StreamUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
|
||||
@ -186,4 +190,12 @@ abstract class AbstractJsonParserTests {
|
||||
assertThatExceptionOfType(JsonParseException.class).isThrownBy(() -> this.parser.parseMap("{\"foo\"}"));
|
||||
}
|
||||
|
||||
@Test // gh-31868
|
||||
void listWithRepeatedOpenArray() throws IOException {
|
||||
String input = StreamUtils.copyToString(
|
||||
AbstractJsonParserTests.class.getResourceAsStream("repeated-open-array.txt"), StandardCharsets.UTF_8);
|
||||
assertThatExceptionOfType(JsonParseException.class).isThrownBy(() -> this.parser.parseList(input)).havingCause()
|
||||
.withMessageContaining("too deeply nested");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,10 @@
|
||||
|
||||
package org.springframework.boot.json;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
|
||||
/**
|
||||
* Tests for {@link GsonJsonParser}.
|
||||
*
|
||||
@ -28,4 +32,10 @@ class GsonJsonParserTests extends AbstractJsonParserTests {
|
||||
return new GsonJsonParser();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Disabled("Gson does not protect against deeply nested JSON")
|
||||
void listWithRepeatedOpenArray() throws IOException {
|
||||
super.listWithRepeatedOpenArray();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.boot.json;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.yaml.snakeyaml.constructor.ConstructorException;
|
||||
@ -53,4 +55,10 @@ class YamlJsonParserTests extends AbstractJsonParserTests {
|
||||
void mapWithKeyAndNoValue() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Disabled("SnakeYaml does not protect against deeply nested JSON")
|
||||
void listWithRepeatedOpenArray() throws IOException {
|
||||
super.listWithRepeatedOpenArray();
|
||||
}
|
||||
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user