diff --git a/src/main/java/com/ankurm/jackson3/part7security/H04StreamReadConstraints.java b/src/main/java/com/ankurm/jackson3/part7security/H04StreamReadConstraints.java new file mode 100644 index 0000000..58615e4 --- /dev/null +++ b/src/main/java/com/ankurm/jackson3/part7security/H04StreamReadConstraints.java @@ -0,0 +1,57 @@ +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() + ")"; + } + } +}