Remove node and recursive limits for YAML
Update `OriginTrackedYamlLoader` to remove node limits and recursive parsing restrictions. SnakeYAML 1.26 introduced these options in order to protect against the "billion laugh attacks" but since we consider `application.yml` files to be trusted, we don't need these restrictions. Fixes gh-23096
This commit is contained in:
@@ -62,12 +62,18 @@ class OriginTrackedYamlLoader extends YamlProcessor {
|
||||
|
||||
@Override
|
||||
protected Yaml createYaml() {
|
||||
BaseConstructor constructor = new OriginTrackingConstructor();
|
||||
LoaderOptions loaderOptions = new LoaderOptions();
|
||||
loaderOptions.setAllowDuplicateKeys(false);
|
||||
loaderOptions.setMaxAliasesForCollections(Integer.MAX_VALUE);
|
||||
loaderOptions.setAllowRecursiveKeys(true);
|
||||
return createYaml(loaderOptions);
|
||||
}
|
||||
|
||||
private Yaml createYaml(LoaderOptions loaderOptions) {
|
||||
BaseConstructor constructor = new OriginTrackingConstructor(loaderOptions);
|
||||
Representer representer = new Representer();
|
||||
DumperOptions dumperOptions = new DumperOptions();
|
||||
LimitedResolver resolver = new LimitedResolver();
|
||||
LoaderOptions loaderOptions = new LoaderOptions();
|
||||
loaderOptions.setAllowDuplicateKeys(false);
|
||||
return new Yaml(constructor, representer, dumperOptions, loaderOptions, resolver);
|
||||
}
|
||||
|
||||
@@ -82,6 +88,10 @@ class OriginTrackedYamlLoader extends YamlProcessor {
|
||||
*/
|
||||
private class OriginTrackingConstructor extends SafeConstructor {
|
||||
|
||||
OriginTrackingConstructor(LoaderOptions loadingConfig) {
|
||||
super(loadingConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object constructObject(Node node) {
|
||||
if (node instanceof ScalarNode) {
|
||||
|
||||
@@ -128,6 +128,35 @@ class OriginTrackedYamlLoaderTests {
|
||||
assertThatExceptionOfType(ConstructorException.class).isThrownBy(this.loader::load);
|
||||
}
|
||||
|
||||
@Test
|
||||
void loadWhenLargeNumberOfNodesLoadsYaml() {
|
||||
StringBuilder yaml = new StringBuilder();
|
||||
int size = 500;
|
||||
yaml.append("defs:\n");
|
||||
for (int i = 0; i < size; i++) {
|
||||
yaml.append(" - def" + i + ": &def" + i + "\n");
|
||||
yaml.append(" - value: " + i + "\n");
|
||||
}
|
||||
yaml.append("refs:\n");
|
||||
for (int i = 0; i < size; i++) {
|
||||
yaml.append(" ref" + i + ":\n");
|
||||
yaml.append(" - value: *def" + i + "\n");
|
||||
}
|
||||
Resource resource = new ByteArrayResource(yaml.toString().getBytes(StandardCharsets.UTF_8));
|
||||
this.loader = new OriginTrackedYamlLoader(resource);
|
||||
Map<String, Object> loaded = this.loader.load().get(0);
|
||||
assertThat(loaded).hasSize(size * 2);
|
||||
}
|
||||
|
||||
@Test
|
||||
void loadWhenRecursiveLoadsYaml() {
|
||||
Resource resource = new ClassPathResource("recursive.yml", getClass());
|
||||
this.loader = new OriginTrackedYamlLoader(resource);
|
||||
Map<String, Object> loaded = this.loader.load().get(0);
|
||||
assertThat(loaded.get("test.a.spring")).hasToString("a");
|
||||
assertThat(loaded.get("test.b.boot")).hasToString("b");
|
||||
}
|
||||
|
||||
private OriginTrackedValue getValue(String name) {
|
||||
if (this.result == null) {
|
||||
this.result = this.loader.load();
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
&def1
|
||||
*def1: a
|
||||
test:
|
||||
a:
|
||||
spring: 'a'
|
||||
b:
|
||||
boot: 'b'
|
||||
Reference in New Issue
Block a user