Part 7: what readValue(json, Object.class) actually does on a default mapper
This commit is contained in:
@@ -0,0 +1,42 @@
|
|||||||
|
package com.ankurm.jackson3.part7security;
|
||||||
|
|
||||||
|
import tools.jackson.databind.json.JsonMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Post: Jackson Security Best Practices — https://ankurm.com/jackson-security-best-practices/
|
||||||
|
* Section: "Never Deserialise Untrusted JSON into Object.class"
|
||||||
|
*
|
||||||
|
* Worth knowing precisely what readValue(json, Object.class) does on a DEFAULT
|
||||||
|
* Jackson 3 mapper, because the answer is reassuring and often misunderstood:
|
||||||
|
* with no default typing active it produces plain Maps, Lists, Strings and numbers.
|
||||||
|
* The danger only returns when default typing is switched on — as H03 shows.
|
||||||
|
*
|
||||||
|
* The rule still stands. Target a specific type; you get validation for free.
|
||||||
|
*/
|
||||||
|
public class H05NeverDeserialiseIntoObject {
|
||||||
|
|
||||||
|
public record MyRequestDto(String action, int quantity) { }
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
JsonMapper mapper = JsonMapper.builder().build();
|
||||||
|
|
||||||
|
String untrusted = "{\"action\":\"ship\",\"quantity\":3,\"extra\":{\"nested\":[1,2]}}";
|
||||||
|
|
||||||
|
Object loose = mapper.readValue(untrusted, Object.class);
|
||||||
|
System.out.println("as Object : " + loose);
|
||||||
|
System.out.println("runtime type: " + loose.getClass().getName()
|
||||||
|
+ " <- a plain Map, no arbitrary class was instantiated");
|
||||||
|
|
||||||
|
MyRequestDto typed = mapper.readValue(untrusted, MyRequestDto.class);
|
||||||
|
System.out.println("as DTO : " + typed);
|
||||||
|
|
||||||
|
// The real benefit of a specific target type: malformed input fails loudly
|
||||||
|
// instead of flowing onward as an untyped Map.
|
||||||
|
try {
|
||||||
|
mapper.readValue("{\"action\":\"ship\",\"quantity\":\"not-a-number\"}", MyRequestDto.class);
|
||||||
|
System.out.println("bad input : UNEXPECTEDLY ACCEPTED");
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("bad input : rejected with " + e.getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user