Интерфейс ObjectInputFilter
- Функциональный интерфейс:
- Это функциональный интерфейс и, следовательно, может быть использован в качестве целевого назначения лямбда-выражения или ссылки на метод.
@FunctionalInterface public interface ObjectInputFilter
Предупреждение: Десериализация недоверенных данных по своей природе опасна и должна быть избегаема. Недоверенные данные должны быть тщательно проверены в соответствии с разделом «Сериализация и десериализация» руководства по безопасным программированию для Java SE. Фильтрование сериализации описывает лучшие практики для защищенного использования фильтров сериализации.
Для защиты от уязвимостей десериализации разработчики приложений нуждаются в четком описании объектов, которые могут быть десериализованы каждой компонентой или библиотекой. Для каждого контекста и варианта использования разработчики должны создавать и применять соответствующий фильтр.
Фабрика и фильтры фильтрации десериализации
Частями фильтрации десериализации являются фильтры, составные фильтры и фабрика фильтров. Каждый фильтр выполняет проверки классов и лимитов ресурсов, чтобы определить статус как отклоненный, разрешенный или неопределенный. Фильтры могут быть составлены из других фильтров и объединять или комбинировать их результаты. Фабрика фильтров отвечает за установление и обновление фильтра для каждогоObjectInputStream. В простых случаях можно установить статический фильтр JVM для всего приложения, не устанавливая фабрику фильтров. Фильтр JVM можно установить либо с помощью системной переменной в командной строке, либо вызвав Config.setSerialFilter. Не нужно указывать пользовательскую фабрику фильтров, по умолчанию используется встроенная фабрика фильтров. Встроенная фабрика фильтров предоставляет статический фильтр JVM для каждого ObjectInputStream.
Например, можно установить фильтр, который разрешает примерные классы, разрешает классы в модуле java.base и отклоняет все остальные классы:
As a command line property:
% java -Djdk.serialFilter="example.*;java.base/*;!*" ... Or programmatically:
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 и фильтром, специфичным для потока. Метод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) {
// Wrap the filter to reject UNDECIDED results
filter = ObjectInputFilter.rejectUndecidedClass(filter);
}
if (next != null) {
// Merge the next filter with the thread filter, if any
// Initially this is the static JVM-wide filter passed from the OIS constructor
// Wrap the filter to reject UNDECIDED results
filter = ObjectInputFilter.merge(next, filter);
filter = ObjectInputFilter.rejectUndecidedClass(filter);
}
return filter;
} 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 wrap it and a filter to recheck for undecided
if (next != null) {
next = ObjectInputFilter.merge(next, curr);
next = ObjectInputFilter.rejectUndecidedClass(next);
return next;
}
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, еслиserialClassnull, -
ALLOWED, если предикат по классу возвращаетtrue, - В противном случае, возвращается
otherStatus.
Пример, для создания фильтра, который будет разрешать любые классы, загруженные из платформенных или bootstrap classloader-ов.
ObjectInputFilter f
= allowFilter(cl -> cl.getClassLoader() == ClassLoader.getPlatformClassLoader() ||
cl.getClassLoader() == null, Status.UNDECIDED);
- Параметры:
-
predicate— предикат для проверки непустого класса -
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, еслиserialClassnull, -
REJECTED, если предикат по классу возвращаетtrue, - В противном случае, возвращается
otherStatus.
Пример, для создания фильтра, который будет отклонять любые классы, загруженные из application classloader-а.
ObjectInputFilter f = rejectFilter(cl ->
cl.getClassLoader() == ClassLoader.ClassLoader.getSystemClassLoader(), Status.UNDECIDED);
- Параметры:
-
predicate— предикат для проверки непустого класса -
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, еслиstatusREJECTED; - Вызвать
anotherFilterдля полученияotherStatus; - Возвратить
REJECTED, еслиotherStatusREJECTED; - Возвратить
ALLOWED, если либоstatusилиotherStatusALLOWED, - В противном случае, вернуть
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() serialClassnull; - Возвратить
REJECTED, если класс не является массивом; - Определить базовый тип компонента, если
serialClassявляется массивом; - Возвратить
UNDECIDED, если базовый тип компонента является примитивным классом; - Вызвать фильтр на
base component typeдля полученияcomponent status; - Возвратить
ALLOWED, если статус компонентаALLOWED; - В противном случае, вернуть
REJECTED.
- Вызвать фильтр на
- Параметры:
-
filter— фильтр - Возвращает:
ObjectInputFilter, отображающийObjectInputFilter.Status.UNDECIDEDстатус наObjectInputFilter.Status.REJECTEDдля классов, в противном случае возвращает статус фильтра- С:
- 17
© 1993, 2021, 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/17/docs/api/java.base/java/io/ObjectInputFilter.html