Интерфейс ObjectInputFilter
- Функциональный интерфейс:
- Это функциональный интерфейс и, следовательно, может быть использован в качестве назначения для лямбда-выражения или ссылки на метод.
@FunctionalInterface public interface ObjectInputFilter
Предупреждение: Десериализация недоверенных данных изначально опасна и должна быть избегнута. Недоверенные данные должны быть тщательно проверены в соответствии с разделом "Сериализация и десериализация" руководства по защищенному программированию Java SE Secure Coding Guidelines for Java SE. Фильтрация сериализации описывает лучшие практики для защищенного использования фильтров сериализации.
Для защиты от уязвимостей десериализации разработчикам приложений необходимо четкое описание объектов, которые могут быть десериализованы каждым компонентом или библиотекой. Для каждого контекста и сценария использования разработчики должны создавать и применять соответствующий фильтр.
Фабрика и фильтры для фильтрации десериализации
Части фильтрации десериализации — это фильтры, составные фильтры и фабрика фильтров. Каждый фильтр выполняет проверки классов и ограничений ресурсов, чтобы определить статус как отклоненный, разрешенный или неопределенный. Фильтры могут быть составлены из других фильтров и объединять или комбинировать их результаты. Фабрика фильтров отвечает за создание и обновление фильтра для каждогоObjectInputStream. В простых случаях можно установить статический фильтр JVM для всего приложения без установки фабрики фильтров. Статический фильтр JVM можно установить либо с помощью системной переменной в командной строке, либо вызвав Config.setSerialFilter. Не требуется указывать пользовательскую фабрику фильтров, по умолчанию используется встроенная фабрика фильтров. Встроенная фабрика фильтров предоставляет статический фильтр JVM для каждого ObjectInputStream.
Например, можно установить фильтр, который разрешает примерные классы, разрешает классы в модуле 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
- См. также:
Краткое описание вложенных классов
| Modifier and Type | Interface | Description |
|---|---|---|
static final class |
ObjectInputFilter.Config |
Класс-утилита для установки и получения фабрики фильтра десериализации JVM-широкого действия, статического JVM-широкого фильтра или создания фильтра из строки шаблона. |
static interface |
ObjectInputFilter.FilterInfo |
FilterInfo предоставляет доступ к информации о текущем объекте, который десериализуется, и статусу ObjectInputStream. |
static enum |
ObjectInputFilter.Status |
Статус проверки класса, длины массива, количества ссылок, глубины и размера потока. |
Краткое описание методов
| Modifier and Type | Method | Description |
|---|---|---|
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.
Пример, для создания фильтра, который позволит любым классам, загруженным из платформенных или bootstrap загрузчиков.
ObjectInputFilter f
= allowFilter(cl -> cl.getClassLoader() == ClassLoader.getPlatformClassLoader() ||
cl.getClassLoader() == null, Status.UNDECIDED);
- Параметры:
-
predicate- предикат для проверки не-null класса -
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- предикат для проверки не-null класса -
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 - Возвращает:
- an
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- фильтр - Возвращает:
- an
ObjectInputFilter, отображающийObjectInputFilter.Status.UNDECIDEDстатус вObjectInputFilter.Status.REJECTEDдля классов, иначе возвращает статус фильтра - С:
- 17
© 1993, 2023, 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/21/docs/api/java.base/java/io/ObjectInputFilter.html