Spec-Zone.ru › OpenJDK 17

Интерфейс 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
См. также:
  • ObjectInputStream.setObjectInputFilter(ObjectInputFilter)

Краткое описание вложенных классов

Модификатор и тип Интерфейс Описание
static final class  ObjectInputFilter.Config
Класс-утилита для установки и получения фабрики фильтра десериализации на уровне JVM, статического фильтра на уровне JVM или для создания фильтра из строки шаблона.
static interface  ObjectInputFilter.FilterInfo
FilterInfo предоставляет доступ к информации о текущем объекте, который десериализуется, и статусу ObjectInputStream.
static enum  ObjectInputFilter.Status
Статус проверки класса, длины массива, количества ссылок, глубины и размера потока.

Краткое описание методов

Модификатор и тип Метод Описание
static ObjectInputFilter allowFilter(Predicate<Class<?>> predicate, ObjectInputFilter.Status otherStatus)
Возвращает фильтр, который возвращает Status.ALLOWED если предикат для класса равен true.
ObjectInputFilter.Status checkInput(ObjectInputFilter.FilterInfo filterInfo)
Проверка класса, длины массива, количества объектных ссылок, глубины, размера потока и другой доступной информации для фильтрации.
static ObjectInputFilter merge(ObjectInputFilter filter, ObjectInputFilter anotherFilter)
Возвращает фильтр, который объединяет статус фильтра и другого фильтра.
static ObjectInputFilter rejectFilter(Predicate<Class<?>> predicate, ObjectInputFilter.Status otherStatus)
Возвращает фильтр, который возвращает Status.REJECTED если предикат для класса равен true.
static ObjectInputFilter rejectUndecidedClass(ObjectInputFilter filter)
Возвращает фильтр, который вызывает заданный фильтр и отображает 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 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, если serialClass null,
  • 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 , если 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, 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API