Какие существуют способы контроля за значениями десериализованного объекта?
Контроль за значениями десериализованного объекта нужен для проверки инвариантов, валидации данных и защиты от подмены сериализованного потока.
1. Интерфейс ObjectInputValidation
Позволяет зарегистрировать валидацию, которая вызывается после полной десериализации объекта.
Пример
public class Person implements Serializable, ObjectInputValidation {
private String name;
private int age;
@Override
public void validateObject() throws InvalidObjectException {
if (age < 0 || age > 150) {
throw new InvalidObjectException("Некорректный возраст: " + age);
}
if (name == null || name.isBlank()) {
throw new InvalidObjectException("Имя не может быть пустым");
}
}
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
in.registerValidation(this, 0); // регистрация валидации
}
}
2. Валидация в readObject
Проверка значений прямо в методе readObject — проще, но вызывается до завершения десериализации всего графа объектов.
3. Шифрование и подпись
Для защиты от подмены данных можно обернуть объект в защитные обёртки:
| Класс | Назначение |
|---|---|
javax.crypto.SealedObject |
Шифрование сериализованного объекта (нужен симметричный ключ) |
java.security.SignedObject |
Цифровая подпись для проверки целостности |
Оба класса сами реализуют Serializable — оборачивают исходный объект, создавая защищённую «упаковку».
4. ObjectInputFilter (Java 9+)
Фильтр десериализации, ограничивающий допустимые классы, глубину графа и размер данных:
Пример
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(
"com.myapp.**;!*" // Разрешить только свои классы
);
ois.setObjectInputFilter(filter);
На собеседовании: назовите
ObjectInputValidationкак основной механизм валидации иObjectInputFilter(Java 9+) как защиту от атак десериализации. УпоминаниеSealedObject/SignedObject— дополнительный плюс.