Skip to content

Commit

Permalink
Protect against deeply nested JSON lists
Browse files Browse the repository at this point in the history
Update `BasicJsonParser` to protect against deeply nested JSON lists
in the same way as Jackson.

Fixes gh-31868
  • Loading branch information
philwebb committed Jul 26, 2022
1 parent 24c4ba3 commit 6966ebd
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 6 deletions.
Expand Up @@ -37,28 +37,33 @@
*/
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);
}

@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);
Expand Down Expand Up @@ -101,7 +106,7 @@ private Map<String, Object> parseMapInternal(String json) {
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;
Expand Down
Expand Up @@ -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;

Expand Down Expand Up @@ -186,4 +190,12 @@ void mapWithKeyAndNoValue() {
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");
}

}
Expand Up @@ -16,6 +16,10 @@

package org.springframework.boot.json;

import java.io.IOException;

import org.junit.jupiter.api.Disabled;

/**
* Tests for {@link GsonJsonParser}.
*
Expand All @@ -28,4 +32,10 @@ protected JsonParser getParser() {
return new GsonJsonParser();
}

@Override
@Disabled("Gson does not protect against deeply nested JSON")
void listWithRepeatedOpenArray() throws IOException {
super.listWithRepeatedOpenArray();
}

}
Expand Up @@ -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;
Expand Down Expand Up @@ -53,4 +55,10 @@ void listWithMalformedMap() {
void mapWithKeyAndNoValue() {
}

@Override
@Disabled("SnakeYaml does not protect against deeply nested JSON")
void listWithRepeatedOpenArray() throws IOException {
super.listWithRepeatedOpenArray();
}

}

Large diffs are not rendered by default.

0 comments on commit 6966ebd

Please sign in to comment.