Интерфейс ObjectInputFilter
- Функциональный интерфейс:
- Это функциональный интерфейс, поэтому его можно использовать в качестве целевого типа для лямбда-выражения или ссылки на метод.
@FunctionalInterface public interface ObjectInputFilter
Предупреждение: десериализация недоверенных данных по своей сути опасна и ее следует избегать. Недоверенные данные следует тщательно проверять в соответствии с разделом «Сериализация и десериализация» документа Рекомендации по безопасному программированию для Java SE. В документе Фильтрация сериализации описаны рекомендации по безопасному использованию фильтров сериализации.
Чтобы защититься от уязвимостей десериализации, разработчикам приложений необходимо иметь четкое описание объектов, которые могут десериализоваться каждым компонентом или библиотекой. Для каждого контекста и варианта использования разработчикам следует создавать и применять подходящий фильтр.
Фабрика и фильтры десериализации
Фильтрация десериализации включает фильтры, составные фильтры и фабрику фильтров. Каждый фильтр проверяет классы и ограничения ресурсов, чтобы определить статус: отклонен, разрешен или не определен. Фильтры можно объединять с другими фильтрами и сводить или комбинировать их результаты. Фабрика фильтров отвечает за установку и обновление фильтра для каждогоObjectInputStream. В простых случаях для всего приложения можно установить статический фильтр уровня JVM, не задавая фабрику фильтров. Фильтр уровня JVM можно задать либо с помощью системного свойства в командной строке, либо вызвав Config.setSerialFilter. Указывать пользовательскую фабрику фильтров не требуется: по умолчанию используется встроенная фабрика. Встроенная фабрика фильтров предоставляет статический фильтр уровня JVM для каждого ObjectInputStream.
Например, можно задать фильтр, который разрешает классы из пакета example, разрешает классы из модуля java.base и отклоняет все остальные классы. В качестве свойства командной строки:
% java -Djdk.serialFilter="example.*;java.base/*;!*" ...
var filter = ObjectInputFilter.Config.createFilter("example.*;java.base/*;!*")
ObjectInputFilter.Config.setSerialFilter(filter);
В приложении с несколькими контекстами выполнения можно предоставить фабрику фильтров, чтобы защитить отдельные контексты, предоставляя для каждого пользовательский фильтр. При создании потока вызывается фабрика фильтров, чтобы определить контекст выполнения по доступной информации, в том числе по текущему состоянию локальных переменных потока, иерархии вызывающих методов, библиотеке, модулю и загрузчику классов. На этом этапе политика фабрики фильтров по созданию или выбору фильтров может выбрать конкретный фильтр или композицию фильтров на основе контекста. Фабрика фильтров десериализации уровня JVM гарантирует, что для каждого ObjectInputStream можно задать фильтр десериализации для конкретного контекста, а также проверять каждый объект, прочитанный из потока.
Вызов фабрики фильтров
Фабрика фильтров уровня JVM — это функция, вызываемая при ObjectInputStream каждого создании и при установке фильтра для потока. Ее параметры — текущий фильтр и запрошенный фильтр; она возвращает фильтр, который будет использоваться для потока. При вызове из конструкторов ObjectInputStream первый параметр равен null, а второй — статическому фильтру уровня JVM. При вызове из ObjectInputStream.setObjectInputFilter первым параметром является фильтр, установленный в данный момент для потока (который был задан в конструкторе), а вторым — фильтр, переданный в ObjectInputStream.setObjectInputFilter. Текущий и новый фильтры могут быть равны null, а фабрика может возвращать null. Обратите внимание, что реализация фабрики фильтров также может использовать любую доступную ей контекстную информацию, например, извлеченную из контекста потока приложения или стека вызовов, для составления и объединения нового фильтра. Она не ограничена использованием только двух своих параметров.
Активная фабрика фильтров десериализации — это:
- Фабрика фильтров, заданная приложением с помощью
ObjectInputFilter.Config.setSerialFilterFactory(BinaryOperator), системного свойстваjdk.serialFilterFactoryили свойства безопасностиjdk.serialFilterFactory. - В противном случае встроенная фабрика фильтров десериализации предоставляет статический фильтр уровня JVM при вызове из конструкторов ObjectInputStream и заменяет статический фильтр при вызове из
ObjectInputStream.setObjectInputFilter(ObjectInputFilter). См. getSerialFilterFactory.
Фильтры
Фильтры можно создавать на основе строки шаблона или предиката класса, чтобы разрешать или отклонять классы.Метод фильтра checkInput(FilterInfo) вызывается ноль или более раз при чтении объектов. Этот метод вызывается для проверки классов, длины каждого массива, количества объектов, считываемых из потока, глубины графа и общего количества байтов, считанных из потока.
Составные фильтры объединяют или проверяют результаты других фильтров. Фильтр merge(filter, anotherFilter) объединяет значения статуса двух фильтров. Фильтр rejectUndecidedClass(filter) проверяет результат фильтра для классов, когда статус равен UNDECIDED. Во многих случаях любой класс, который фильтр не ALLOWED, следует REJECTED.
Фильтр десериализации определяет, разрешены или отклонены аргументы, и должен возвращать соответствующий статус: ALLOWED или REJECTED. Если фильтр не может определить статус, он должен возвращать UNDECIDED. Фильтры следует разрабатывать с учетом конкретного варианта использования и ожидаемых типов. Фильтру, предназначенному для конкретного случая, может быть передан класс, не входящий в область его применения. Если цель фильтра — отклонять классы, он может отклонить соответствующий условию класс-кандидат и сообщить UNDECIDED для остальных. Фильтр может быть вызван, когда класс равен null, arrayLength равен -1, а глубина, число ссылок и размер потока имеют определенные значения, и возвращать статус, отражающий только одно или некоторые из этих значений. Это позволяет фильтру точно указывать, на основании чего он принимает решение, и использовать другие фильтры, не принуждая их возвращать статус «разрешен» или «отклонен».
Примеры модели фильтрации
Для простых приложений может быть достаточно одного предварительно заданного фильтра со списком разрешенных или отклоненных классов, чтобы снизить риск десериализации неожиданных классов.Для приложения, состоящего из нескольких модулей или библиотек, структуру приложения можно использовать для определения классов, которые следует разрешать или отклонять каждому ObjectInputStream в каждом контексте приложения. Фабрика фильтров десериализации вызывается при создании каждого потока и может изучить поток или программу, чтобы определить фильтр для конкретного контекста. Возможны следующие примеры:
- В локальном состоянии потока можно хранить фильтр, который следует применить или объединить с фильтром конкретного потока. Приложение или библиотеки могут помещать фильтры в виртуальный стек и извлекать их из него.
- Фабрика фильтров может определить вызывающий метод десериализации и использовать контекст модуля или библиотеки, чтобы выбрать фильтр или составить подходящий фильтр для конкретного контекста. Механизм может определять вызывающий код с ограниченным или неограниченным доступом к сериализованным классам и выбирать фильтр соответственно.
Пример фильтрации каждой операции десериализации в потоке
В этом классе показано, как предоставленная приложением фабрика фильтров может объединять фильтры, чтобы проверять каждую операцию десериализации, выполняемую в потоке. Класс определяет переменную с локальной областью потока для хранения фильтра, специфичного для потока, и создает фабрику фильтров, объединяющую этот фильтр со статическим фильтром уровня JVM и фильтром конкретного потока, отклоняя любые классы, не обработанные этими двумя фильтрами. Если для потока задан фильтр и он не разрешает и не отклоняет класс, применяется объединенный фильтр уровня JVM и фильтр потока. МетодdoWithSerialFilter настраивает фильтр, специфичный для потока, и вызывает предоставленный приложением Runnable. public static final class FilterInThread implements BinaryOperator<ObjectInputFilter> {
private final ThreadLocal<ObjectInputFilter> filterThreadLocal = new ThreadLocal<>();
// Construct a FilterInThread deserialization filter factory.
public FilterInThread() {}
// Returns a composite filter of the static JVM-wide filter, a thread-specific filter,
// and the stream-specific filter.
public ObjectInputFilter apply(ObjectInputFilter curr, ObjectInputFilter next) {
if (curr == null) {
// Called from the OIS constructor or perhaps OIS.setObjectInputFilter with no current filter
var filter = filterThreadLocal.get();
if (filter != null) {
// Merge to invoke the thread local filter and then the JVM-wide filter (if any)
filter = ObjectInputFilter.merge(filter, next);
return ObjectInputFilter.rejectUndecidedClass(filter);
}
return (next == null) ? null : ObjectInputFilter.rejectUndecidedClass(next);
} else {
// Called from OIS.setObjectInputFilter with a current filter and a stream-specific filter.
// The curr filter already incorporates the thread filter and static JVM-wide filter
// and rejection of undecided classes
// If there is a stream-specific filter merge to invoke it and then the current filter.
if (next != null) {
return ObjectInputFilter.merge(next, curr);
}
return curr;
}
}
// Applies the filter to the thread and invokes the runnable.
public void doWithSerialFilter(ObjectInputFilter filter, Runnable runnable) {
var prevFilter = filterThreadLocal.get();
try {
filterThreadLocal.set(filter);
runnable.run();
} finally {
filterThreadLocal.set(prevFilter);
}
}
}
Использование фабрики фильтров
Чтобы использовать служебный классFilterInThread, создайте экземпляр и настройте его как фабрику фильтров уровня JVM. Метод doWithSerialFilter вызывается с фильтром, разрешающим классы примера приложения и основные классы: // Create a FilterInThread filter factory and set
var filterInThread = new FilterInThread();
ObjectInputFilter.Config.setSerialFilterFactory(filterInThread);
// Create a filter to allow example.* classes and reject all others
var filter = ObjectInputFilter.Config.createFilter("example.*;java.base/*;!*");
filterInThread.doWithSerialFilter(filter, () -> {
byte[] bytes = ...;
var o = deserializeObject(bytes);
});
Если не указано иное, передача аргумента null методу этого интерфейса или его вложенных классов приводит к выбрасыванию исключения NullPointerException.
- Начиная с:
- 9
- См. также:
Краткое описание вложенных классов
| Модификатор и тип | Интерфейс | Описание |
|---|---|---|
static final class |
ObjectInputFilter.Config |
Служебный класс для установки и получения фабрики фильтров десериализации уровня JVM, статического фильтра уровня JVM или создания фильтра на основе строки шаблона. |
static interface |
ObjectInputFilter.FilterInfo |
FilterInfo предоставляет доступ к сведениям о текущем десериализуемом объекте и статусе ObjectInputStream. |
static enum |
ObjectInputFilter.Status |
Статус проверки класса, длины массива, количества ссылок, глубины и размера потока. |
Краткое описание методов
| Модификатор и тип | Метод | Описание |
|---|---|---|
static ObjectInputFilter |
allowFilter |
Возвращает фильтр, который возвращает Status.ALLOWED, если предикат для класса true. |
ObjectInputFilter.Status |
checkInput |
Проверяет класс, длину массива, количество ссылок на объекты, глубину, размер потока и другие доступные сведения для фильтрации. |
static ObjectInputFilter |
merge |
Возвращает фильтр, объединяющий статусы фильтра и другого фильтра. |
static ObjectInputFilter |
rejectFilter |
Возвращает фильтр, который возвращает Status.REJECTED, если предикат для класса true. |
static ObjectInputFilter |
rejectUndecidedClass |
Возвращает фильтр, который вызывает заданный фильтр и для классов преобразует UNDECIDED в REJECTED с учетом некоторых особых случаев, а в остальных случаях возвращает статус. |
Подробное описание методов
checkInput
ObjectInputFilter.Status checkInput(ObjectInputFilter.FilterInfo filterInfo)
Status.ALLOWED, Status.REJECTED или Status.UNDECIDED. Если filterInfo.serialClass() равно non-null, имеется класс, который нужно проверить. Если serialClass() равно null, класс отсутствует, а сведения содержат только метрики, связанные с глубиной десериализуемого графа, количеством ссылок и размером прочитанного потока.
- Примечание к API:
- Каждый фильтр, реализующий
checkInput, должен возвращать одно из значенийObjectInputFilter.Status. Возврат значенияnullможет привести к исключениюNullPointerExceptionили другому непредсказуемому поведению. - Параметры:
-
filterInfo— предоставляет сведения о текущем десериализуемом объекте, если он есть, и о статусеObjectInputStream - Возвращает:
-
Status.ALLOWED, если объект принят,Status.REJECTED, если отклонен,Status.UNDECIDED, если решение не принято.
allowFilter
static ObjectInputFilter allowFilter(Predicate<Class<?>> predicate, ObjectInputFilter.Status otherStatus)
Status.ALLOWED, если предикат для класса true. Фильтр возвращает ALLOWED или otherStatus на основании предиката для класса non-null и UNDECIDED, если класс null. При вызове метода фильтра checkInput(info) предикат применяется к info.serialClass(). Возвращаемый статус:
-
UNDECIDED, еслиserialClassравенnull, -
ALLOWED, если предикат для класса возвращаетtrue, - В противном случае возвращается
otherStatus.
Например, чтобы создать фильтр, разрешающий любой класс, загруженный загрузчиком классов платформы или загрузчиком классов начальной загрузки.
ObjectInputFilter f
= allowFilter(cl -> cl.getClassLoader() == ClassLoader.getPlatformClassLoader() ||
cl.getClassLoader() == null, Status.UNDECIDED);
- Параметры:
-
predicate— предикат для проверки ненулевого Class -
otherStatus— статус, который следует использовать, если предикатfalse - Возвращает:
- фильтр, который возвращает
ALLOWED, если предикат для классаtrue - Начиная с:
- 17
rejectFilter
static ObjectInputFilter rejectFilter(Predicate<Class<?>> predicate, ObjectInputFilter.Status otherStatus)
Status.REJECTED, если предикат для класса true. Фильтр возвращает REJECTED или otherStatus на основании предиката для класса non-null и UNDECIDED, если класс null. При вызове метода фильтра checkInput(info) предикат применяется к serialClass(). Возвращаемый статус: -
UNDECIDED, еслиserialClassравенnull, -
REJECTED, если предикат для класса возвращаетtrue, - В противном случае возвращается
otherStatus.
Например, чтобы создать фильтр, отклоняющий любой класс, загруженный загрузчиком классов приложения.
ObjectInputFilter f = rejectFilter(cl ->
cl.getClassLoader() == ClassLoader.ClassLoader.getSystemClassLoader(), Status.UNDECIDED);
- Параметры:
-
predicate— предикат для проверки ненулевого Class -
otherStatus— статус, который следует использовать, если предикатfalse - Возвращает:
- возвращает фильтр, который возвращает
REJECTED, если предикат для классаtrue - Начиная с:
- 17
merge
static ObjectInputFilter merge(ObjectInputFilter filter, ObjectInputFilter anotherFilter)
another равен null, возвращается filter. В противном случае возвращается filter, объединяющий пару фильтров non-null. Возвращаемый фильтр реализует метод checkInput(FilterInfo) следующим образом: - Вызывает
filterдляFilterInfo, чтобы получить егоstatus; - Возвращает
REJECTED, еслиstatusравенREJECTED; - Вызывает
anotherFilter, чтобы получитьotherStatus; - Возвращает
REJECTED, еслиotherStatusравенREJECTED; - Возвращает
ALLOWED, еслиstatusилиotherStatusравенALLOWED, - В противном случае возвращает
UNDECIDED
- Параметры:
-
filter— фильтр -
anotherFilter— фильтр, объединяемый с этим фильтром; может быть равенnull - Возвращает:
ObjectInputFilter, объединяющий статусы этого фильтра и другого фильтра- Начиная с:
- 17
rejectUndecidedClass
static ObjectInputFilter rejectUndecidedClass(ObjectInputFilter filter)
UNDECIDED в REJECTED с учетом некоторых особых случаев, а в остальных случаях возвращает статус. Если класс не является примитивным и не является массивом, возвращается статус REJECTED. Для примитивных классов и классов массивов выполняются дополнительные проверки; подробности см. в списке ниже. При десериализации объекта класс принимается, если фильтр возвращает UNDECIDED. Добавление фильтра, отклоняющего неопределенные результаты для классов, которые не были ни разрешены, ни отклонены, может предотвратить обход фильтра классами.
- Требования к реализации:
- Возвращаемый фильтр реализует метод
checkInput(FilterInfo)следующим образом:- Вызывает фильтр для
FilterInfo, чтобы получить егоstatus; - Возвращает
status, если статус равенREJECTEDилиALLOWED; - Возвращает
UNDECIDED, еслиfilterInfo.getSerialClass() serialClassравенnull; - Возвращает
REJECTED, если класс не является массивом; - Определяет базовый тип компонента, если
serialClassявляется массивом; - Возвращает
UNDECIDED, если базовый тип компонента является примитивным классом; - Вызывает фильтр для
base component type, чтобы получить егоcomponent status; - Возвращает
ALLOWED, если статус компонента равенALLOWED; - В противном случае возвращает
REJECTED.
- Вызывает фильтр для
- Параметры:
-
filter— фильтр - Возвращает:
ObjectInputFilter, преобразующий статусObjectInputFilter.Status.UNDECIDEDвObjectInputFilter.Status.REJECTEDдля классов; в остальных случаях возвращает статус фильтра- Начиная с:
- 17
© 1993, 2025, Oracle and/or its affiliates. All rights reserved.
Documentation extracted from Debian's OpenJDK Development Kit package.
Licensed under the GNU General Public License, version 2, with the Classpath Exception.
Various third party code in OpenJDK is licensed under different licenses (see Debian package).
Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.
https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/io/ObjectInputFilter.html