37 runnable examples covering the eight feature posts on ankurm.com, verified against Jackson 3.2.1 on Temurin 21.0.5. Every output committed under docs/ was produced by run-all.sh. Also documents 11 places where the published snippets do not compile or do not behave as printed against a real Jackson 3 build - most notably that writeValueAsString(List<Base>) silently drops the polymorphic type discriminator, so the post's serialised output cannot be read back.
58 lines
2.6 KiB
Java
58 lines
2.6 KiB
Java
package com.ankurm.jackson3.part7security;
|
|
|
|
import tools.jackson.core.StreamReadConstraints;
|
|
import tools.jackson.core.json.JsonFactory;
|
|
import tools.jackson.databind.json.JsonMapper;
|
|
|
|
/**
|
|
* BEYOND THE POST — the hardening the security post does not mention.
|
|
*
|
|
* Gadget attacks are not the only deserialisation risk. A small payload can also
|
|
* exhaust the stack or the heap: deeply nested arrays, gigantic numbers, enormous
|
|
* strings. Jackson 3 ships StreamReadConstraints with defaults for all three, and
|
|
* they are tunable. Any service accepting external JSON should know what they are.
|
|
*/
|
|
public class H04StreamReadConstraints {
|
|
|
|
public static void main(String[] args) {
|
|
StreamReadConstraints defaults = StreamReadConstraints.defaults();
|
|
System.out.println("--- Jackson 3 defaults ---");
|
|
System.out.println("max nesting depth : " + defaults.getMaxNestingDepth());
|
|
System.out.println("max number length : " + defaults.getMaxNumberLength());
|
|
System.out.println("max string length : " + defaults.getMaxStringLength());
|
|
System.out.println("max name length : " + defaults.getMaxNameLength());
|
|
System.out.println("max doc length : " + defaults.getMaxDocumentLength()
|
|
+ " (-1 = unlimited)");
|
|
System.out.println();
|
|
|
|
JsonMapper plain = JsonMapper.builder().build();
|
|
String deep = "[".repeat(1200) + "]".repeat(1200);
|
|
System.out.println("1200-deep nesting, default limits -> " + attempt(plain, deep));
|
|
|
|
// Tighten the limits for an endpoint that should never see nested data.
|
|
JsonFactory strictFactory = JsonFactory.builder()
|
|
.streamReadConstraints(StreamReadConstraints.builder()
|
|
.maxNestingDepth(10)
|
|
.maxStringLength(2_000)
|
|
.build())
|
|
.build();
|
|
JsonMapper strict = JsonMapper.builder(strictFactory).build();
|
|
|
|
System.out.println("20-deep nesting, strict limits -> "
|
|
+ attempt(strict, "[".repeat(20) + "]".repeat(20)));
|
|
System.out.println("5-deep nesting, strict limits -> "
|
|
+ attempt(strict, "[".repeat(5) + "]".repeat(5)));
|
|
System.out.println("3KB string, strict limits -> "
|
|
+ attempt(strict, "\"" + "x".repeat(3_000) + "\""));
|
|
}
|
|
|
|
private static String attempt(JsonMapper mapper, String json) {
|
|
try {
|
|
mapper.readTree(json);
|
|
return "accepted";
|
|
} catch (Exception e) {
|
|
return "rejected (" + e.getClass().getSimpleName() + ")";
|
|
}
|
|
}
|
|
}
|