Part 7: the safe pattern - compile-time subtype registry
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
package com.ankurm.jackson3.part7security;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import tools.jackson.databind.json.JsonMapper;
|
||||
|
||||
/**
|
||||
* Post: Jackson Security Best Practices — https://ankurm.com/jackson-security-best-practices/
|
||||
* Section: "Use @JsonTypeInfo Instead of Default Typing"
|
||||
*
|
||||
* The safe pattern: the permitted types are fixed at compile time, so no JSON payload
|
||||
* can introduce a class name of its own.
|
||||
*/
|
||||
public class H01SafePolymorphismByAnnotation {
|
||||
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = EmailNotification.class, name = "email"),
|
||||
@JsonSubTypes.Type(value = SmsNotification.class, name = "sms")
|
||||
})
|
||||
public abstract static class Notification { }
|
||||
|
||||
public static class EmailNotification extends Notification {
|
||||
public String recipientEmail;
|
||||
@Override public String toString() { return "EmailNotification[" + recipientEmail + "]"; }
|
||||
}
|
||||
|
||||
public static class SmsNotification extends Notification {
|
||||
public String recipientPhone;
|
||||
@Override public String toString() { return "SmsNotification[" + recipientPhone + "]"; }
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
JsonMapper mapper = JsonMapper.builder().build();
|
||||
|
||||
System.out.println("email : " + mapper.readValue(
|
||||
"{\"type\":\"email\",\"recipientEmail\":\"a@example.com\"}", Notification.class));
|
||||
System.out.println("sms : " + mapper.readValue(
|
||||
"{\"type\":\"sms\",\"recipientPhone\":\"+441234567890\"}", Notification.class));
|
||||
|
||||
// A class name supplied by an attacker is not a registered logical name.
|
||||
try {
|
||||
mapper.readValue("{\"type\":\"com.malicious.Gadget\"}", Notification.class);
|
||||
System.out.println("attack: UNEXPECTEDLY ACCEPTED");
|
||||
} catch (Exception e) {
|
||||
System.out.println("attack: rejected with " + e.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user