Spec-Zone.ru › OpenJDK 21

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

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

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(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 загрузчиков.

    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

Spec-Zone.ru

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