Здравствуйте, я криворукий.
Разве Log4j не пропускает лазейку? Затем несколько дней назад маленький друг спросил меня: я использую Lombok @Slf4j в своем проекте. Повлияет ли это на него?
Какое совпадение вы сказали, я тоже использовал эту аннотацию, так что я взглянул на нее в свое время.
Начнем с вывода: влияет он или нет, зависит от пакета log4j2, от которого зависит ваш проект, и не имеет никакого отношения к Lombok.
Кроме того, "пожалуйста, подумайте дважды, прежде чем задавать вопросы, не тратьте наше время, не задавайте вопросы, которые вы можете решить самостоятельно" - это не то, что я сказал, это сказал автор Ломбока:
Почему он сказал такие слегка злые слова?
Я покажу тебе.
из вопроса
Вы находите проект Lombok на github и проверяете его проблемы, чтобы убедиться, что проблема с log4j закреплена:
Итак, по этому вопросу я начну с этого вопроса, на который есть авторитетный ответ от сопровождающего Ломбока.
Название этого выпуска переводится как:
Вывод: Что касается проблемы 0day с log4j, то сам Ломбок не затронут.
Обратите внимание, что в этом есть очень интригующее слово: сам.
Обычно мы говорим, что Lombok не затрагивается, почему мы должны добавлять себя?
Здесь есть история.
Во-первых, в 17:41 10 декабря, днем, когда уязвимость была обнаружена, приятель поднял этот вопрос в выпуске Ломбока:
Он сказал: Айронс, что-то случилось, и в log4j обнаружена огромная лазейка, спешите исправить ее.
Затем выскочил старик по имени Rawi01 и сказал:
Чувак, можешь объяснить, как эта уязвимость влияет на Ломбок? Насколько я знаю, log4j нужен только для запуска тестов без ошибок компиляции.
Этот старик явно хорошо знает Ломбок, он указал на ключевой момент: Ломбок не полагается на log4j.
Но тут кто-то заметил:
Ломбок предоставляет аннотацию @log4j. Эта штука использует библиотеку Log4J, ведь она используется для логирования.
Такая аннотация действительно есть, давайте посмотрим на нее:
Обычно я использую аннотацию @Slf4j, но она предоставляет и другие аннотации журналов, которые не указаны первыми и будут обсуждаться позже.
Текущая основная задача это вопрос, а дальше смотреть вниз.
Далее подошел приятель, который контролирует поле и увидел, что он сказал:
Сначала он упомянул приятеля, который сказал @log4j, аннотированный ранее, и объяснил ему, что, хотя Lombok будет генерировать код для создания экземпляра регистратора, мы не отправляем, не распространяем и не требуем какой-либо конкретной версии, если пользователь хочет использовать для этой аннотации , они должны предоставить свои собственные соответствующие зависимости.
Здесь у меня есть три слова, которые я еще не перевел: грузить, распространять или требовать.
require на самом деле очень просто, это требование.
Это означает, что мы не требуем от пользователей указывать указанную версию зависимости при ее использовании. Грубо говоря, если вы хотите использовать @Log4j, то предоставьте соответствующую зависимость, а версия этой зависимости Ломбоку все равно.
Остальная часть корабля дословно переводится как «доставка», а «распределение» означает «распределение».
Поясню это картинкой:
Как видите, в проекте я ссылаюсь на Lombok, но он транзитивно не зависит ни от каких других пакетов. Это не похоже на то, что за spring-boot-starter следует целая куча вещей.
Я так понимаю, это то, что он хочет сказать: мы не отправляем, не распространяем и не требуем какой-либо конкретной версии.
А затем продолжил: «Мы находим версию log4j2 в нашей кодовой базе, но она используется только в тестовом коде, чтобы иметь возможность скомпилировать сгенерированный код без ошибок.
В конце концов, приходит прихождение: будьте уверены, старые утюги, ломбок все еще безопасны для использования. Но я думаю, что даже хоть log4j ссылается в тестовый код, зависимости должны быть обновлены до безопасной версии.
Как, вы чувствуете, что этот старик говорит с неоспоримым чувством уверенности.
Прочитав этот ответ, у меня такое ощущение, я смутно чувствую, что это большой парень.
Итак, я взглянул на предысторию этого старика:
Первоначально я искал ответы на его домашней странице на github, но не нашел никаких проектов, связанных с Ломбоком.
А подписчиков всего 49, что не соответствует данным здоровяка:
Поэтому я открыл браузер и поискал: Роэл Спилкер Ломбок.
Нашел это:
Я только что узнал, чувак, он отец Ломбока, неудивительно, что он так много говорит.
Также нашел лакомый кусочек: они ранее предложили Oracle идею для Lombok, но она была отклонена. Чиновники этого не поддерживают, они должны подняться и сделать это сами.
Сейчас доля рынка Ломбока по-прежнему очень высока, это можно считать успехом.
К тому же, собственно, здесь можно непосредственно увидеть его личность:
Сотрудник есть соавтор. Его ответ может быть эквивалентен официальному ответу.
До сих пор все развивается относительно гладко.Чиновник спустился, чтобы ответить на этот вопрос лично, и четко заявил:
Можно сделать вывод, что цветок израсходован.
Однако я боялся, что она появится, но то, что произошло позже, меня немного возмутило.
Во-первых, Brother SunriseChair убил:
Сначала он процитировал ответ автора и сказал: если вы объявите зависимость Lombok в своем maven или gradle, не будет ли также включена зависимость Log4j? Может ли это быть единственной зависимостью от classpath, которая также используется кодом, сгенерированным Lombok? Пожалуйста, поправьте меня, если я ошибаюсь...
Что он хочет выразить.
Прежде всего, я думаю, что после прочтения ответа автора он думает, что Lombok зависит от Log4j, поэтому его основной вопрос: если я сошлюсь на Lombok, не будут ли также переданы зависимости Log4j?
Но автор сказал: в нашей кодовой базе есть версия, но она используется только в тестовых классах.
Пока вы немного знаете о принципе работы проектов с открытым исходным кодом, вы знаете, что части, связанные с тестами, не будут предоставлены.Если вы хотите увидеть тестовый класс, вам нужно вытащить исходный код проекта.
Просто, если вы полагаетесь на Ломбок через Maven, вы не должны его увидеть.
Тут же вышел старик по имени Руан Нунес, чтобы заправить пистолет и предложил второе убийство, сказав, что искал эту штуку во всем проекте:
Эта конфигурация ошибочна.
Затем автор последовательно ответил на эти два вопроса:
Прежде всего, братан, который сказал, что Lombok зависит от log4j: у Lombok нет зависимостей от log4j или любой другой библиотеки. Если вы используете аннотацию @Log4j в своем коде, но не зависите от log4j прямо или косвенно, ваша компиляция выдаст сообщение об ошибке.
Что касается этого момента, предыдущий скриншот анализа зависимостей также объяснил, поэтому я не буду публиковать его снова.
И затем, приятель, который нашел ошибку, послушай: в том же каталоге, где ты нашел эту ошибку, есть текстовый файл, но как только ты на него посмотришь, ты понимаешь, что мы не собираемся делать этот файл частью нашего релиза.
Я так понимаю, что его вообще не выпустят.Даже если есть лазейки, ничего страшного для пользователей Ломбока нет, верно?
Я также искал файл, который сказал автор, а именно:
В этом документе четко сказано: не является частью самого ломбока.
Если предыдущие два вопроса уже заставили автора чувствовать себя немного несчастным, то следующий вопрос может стать переломным моментом, выполнить три убийства и забрать их одной волной:
Этот приятель подошел и сказал: Старый утюг, у меня вопрос. Я использую аннотацию @slf4j, связана ли эта ошибка со мной?
Нет, нет, нет, у меня повышенное давление.
Я думаю, что этот парень не прочитал предыдущие ответы вообще, прежде чем задавать вопрос. Если он задал этот вопрос, прежде чем автор объяснил это дважды, то я думаю, что это полностью понятно.
Но исходя из того, что автор дважды объяснял в этом выпуске, что «Ломбок не затронут», он захлопнул, и это был крит:
Чувак, что-то не так с этой аннотацией, которую я использовал?
Когда я пишу это, у меня немного повысилось давление.
Это особенно похоже на сцену, в которой я ранее обсуждал с другими в группе сбой транзакции. Дискуссия подошла к концу, и вдруг выскочил приятель и выбросил фрагмент кода. Способ написания этого фрагмента — классический. Сценарии аннотации транзакций недействительны, и это часть того, что мы только что обсудили.
Зная, что мы обсуждаем это, даже если вы прокрутите немного вверх, не лучше ли задать вопрос после понимания контекста?
Не будем заходить слишком далеко, может быть, я преувеличиваю, но я думаю, что искусству задавать вопросы должен научиться каждый.
Возвращаясь к нашей основной сюжетной линии, посмотрите, как автор отвечает на этот вопрос:
Он сказал: Старый Галстук, я не могу помочь тебе с этим вопросом. Я ничего не знаю об этой ошибке и даже не понимаю, почему вы думаете, что она влияет и на @Slf4j.
Что я могу вам сказать, так это то, что Lombok не использует, не передает и не требует зависимостей от этих библиотек.
Мы работаем, генерируя ваш «невидимый исходный код».
Если у вас есть основания подозревать, что аналогичная проблема может возникнуть и в их продукте, обратитесь к сопровождающим Slf4j.
Не знаю, мое личное ощущение, но мне кажется, что автор немного разозлился, когда ответил на вопрос: что это за проблемы? Я ответил дважды, и это не влияет? Почему мне кажется, что пользователи моего проекта не понимают основ Ломбока?
После того, как автор ответил на опрометчивый вопрос, тот ответил вежливо:
Спасибо, старое железо, я проверил, я использую логбэк SpringBoot по умолчанию.
Автор также закрепил эту проблему и изменил название этой проблемы.
Итак, после некоторой предыдущей интерпретации, теперь вы снова смотрите на этот заголовок:
Почему автор делает ударение на «себя», потому что Lombok действительно предоставляет функцию ведения журнала, но это не имеет никакого отношения к Lombok относительно того, на какой пакет или версию пакета ссылается. Сам Ломбок безопасен.
В конце концов, автор дал оценку уязвимости log4j последней оценке Ломбока в качестве заключительного замечания:
Переведите ключевые вещи для вас.
Эта уязвимость существует только в пакете кода Log4j ниже версии 2.16.0 и не существует ни в какой другой среде ведения журналов.
Lombok транзитивно не зависит ни от каких пакетов Log4j и ни от чего не объявляет зависимости.
Если вы используете какие-либо аннотации Lombok, такие как @Log4j, Lombok сгенерирует код, использующий эти библиотеки, но ваш проект должен включать зависимости от этих библиотек, иначе код, сгенерированный Lombok, не будет компилироваться.
Точно так же вы несете ответственность за наличие этих пакетов в среде выполнения, иначе инициализация класса может завершиться ошибкой.
В тестовом коде Lombok у нас была версия, содержащая эту уязвимость, но, поскольку тест не обрабатывал никакие действия пользователя (тест был жестко запрограммирован), а сгенерированный код даже не выполнялся, выполнение теста не В результате на компьютере, выполняющем тест RCE (Уязвимость удаленного выполнения кода/команды), отображается значок .
Так что, старые утюги, сам Ломбок никаких изменений вносить не надо, как и не берет на себя никакой ответственности за безопасность вашего проекта, ведь пакет вводится не нами.
Если вы не согласны с текущей оценкой, пожалуйста, добавьте комментарий по этому вопросу.
Тем не менее, убедитесь, что вы прочитали другие комментарии и убедитесь, что вы понимаете вопрос.
Последние два предложения, выделенные, мне очень нравятся вот эти два предложения:
Пожалуйста, дважды подумайте, прежде чем задавать вопросы, не тратьте наше время понапрасну, не задавайте вопросы, в которых сможете разобраться самостоятельно.
Если вы считаете, что мы что-то упустили или у вас есть новая информация, сообщите об этом.
Затем вы замечаете подзаголовок, который автор использует здесь: «Уравновешивание».
Перевод "сбалансированное поведение", какого черта?
НЕТ НЕТ НЕТ:
Маленький сленг для всех, не будь вежливым.
Дополнительные инструкции
Основная сюжетная линия была закончена ранее, теперь позвольте мне сделать некоторые дополнительные пояснения.
Поговорим о заметках о журнале, которые не были показаны ранее.
На самом деле аннотаций про логи в Ломбоке достаточно много, можно прямо почитать официальную документацию:
Аннотаций так много, что рассказывать о них по одной неинтересно, для демонстрации я выберу @Slf4j и @Log4j2.
Во-первых, мы можем создать чистый проект SpringBoot, содержащий только эти две зависимости:
В это время, если я ничего не перемещаю, просто немного изменю класс запуска:
Затем, чтобы устранить мешающие элементы, я настроил уровень печати журнала на Error:
logging.level.root=error
Также отключите вывод баннера:
spring.main.banner-mode=off
баннер вот такая штука:
В это время проект запущен, и вывод журнала выглядит следующим образом:
Вы можете видеть, что журнал, который мы используем в настоящее время, — это logback, причина, о которой я также упоминал в предыдущей статье, потому что реализация журнала по умолчанию, используемая Springboot, — это logback.
Это также видно из зависимостей проекта:
Кроме того, обратите внимание, что я намеренно вырезал часть импорта.За исключением аннотации @Slf4j, здесь нет аннотации, связанной с журналом.
Затем обращу внимание на скомпилированный в это время файл класса:
Пакеты, связанные с slf4j, добавляются автоматически, а затем генерируется следующая строка кода:
private static final Logger log = LoggerFactory.getLogger(LogdemoApplication.class);
На данный момент я не знаю, задумывались ли вы о вещах, связанных с аннотациями, во время компиляции, но не паникуйте, вот первый, кто нажмет на список.
Позвольте мне спросить вас: почему он может вводить пакеты, связанные с slf4j?
Потому что я завишу от этого:
Ну а если я в это время удалю основные зависимости logback, что будет, думаете не скомпилируется?
Не скомпилирован, потому что пакет SLF4J все еще там, это просто бревенчатый фасад.
Однако при запуске будет выдано исключение, потому что конкретный класс реализации, связанный с журналом, не может быть найден:
Что, если я захочу реализовать это с ведением журнала log4j2?
Также написано в предыдущей статье:
Удалите зависимости Springboot по умолчанию, а затем импортируйте пакет Log4j2.
На данный момент график зависимостей проекта такой, видно, что нет logback-core, только log4j-core:
Запустите проект еще раз, и реализация ведения журнала станет Log4j:
Вы заметили, что я не переместил ни одной строки кода, кроме зависимости pom, а структура ведения журнала изменилась с logback на log4j.
И файл класса не изменился, поэтому скриншоты делать не буду.
Это заслуга Slf4j, это значение слова «фасад», и именно поэтому рекомендуется использовать Slf4j в своих проектах, а не конкретные реализации журналов, такие как logback и log4j.
Далее поговорим об аннотации @Log4j2.
Мы по-прежнему восстанавливаем зависимость в исходное чистое состояние, а именно:
Затем мы изменили аннотацию на @Log4j2, но пакет Log4j-core еще не был представлен в нашем проекте, так что вы думаете, возникнут проблемы?
Ничего страшного, можем посмотреть.
Сначала взгляните на вывод:
В настоящее время класс реализации журнала — SLF4JLogger.
Откуда взялась эта штука?
Взгляните на файл класса:
Эти два класса взяты из пакета log4j-api, и из-за существования пакета log4j-to-slf4j окончательный класс реализации связан с SLF4JLogger:
Если я удалю пакет log4j-api, как вы думаете, он не скомпилируется?
Его нельзя компилировать, потому что пакета не существует, а файл класса найти нельзя:
Если я не хочу использовать класс SLF4JLogger, я хочу использовать настоящий log4j.
Просто введите зависимости log4j:
Ну, я сказал так много ерунды раньше, я взял на себя труд исключить и ввести для вас пакеты, связанные с журналом, и показать вам вывод, и весь процесс не включал изменение пакета Lombok, просто чтобы подтвердить два предложения :
Если вы используете какие-либо аннотации Lombok, такие как @Log4j, Lombok сгенерирует код, использующий эти библиотеки, но ваш проект должен включать зависимости от этих библиотек, иначе код, сгенерированный Lombok, не будет компилироваться.
Например, я удалил пакет log4j-api раньше, он скомпилировался?
Точно так же вы несете ответственность за наличие этих пакетов в среде выполнения, иначе инициализация класса может завершиться ошибкой.
Например, я удалил пакет logback-core ранее, и при компиляции проблем нет, но когда служба запускается, она выдает исключение, что класс не может быть найден?
Доказывает ли это снова:
Расскажите о принципе
Ранее я упомянул «аннотацию времени компиляции», я не знаю, понимаете ли вы эту вещь.
Это нормально не знать, потому что, когда мы пишем бизнес-код, мы редко настраиваем аннотации во время компиляции.
Основным принципом работы Lombok является аннотация во время компиляции.
На самом деле, я мало что знаю об этом, но я лишь приблизительно знаю, как это работает, и я не изучал исходный код глубоко.
Но я могу поделиться с вами двумя вещами, на которые следует обратить внимание, и куда пойти, чтобы узнать об этом.
Первое место, на которое стоит обратить внимание, это:
Исходный код комментариев к логу находится в этом разделе.Вы видите, что это очень странно.Эти файлы заканчиваются на SCL.lombok.Что это?
Это тщательно продуманный ломбок.На самом деле, это все файлы классов, но чтобы не загрязнять пользовательские проекты, он сделал специальную обработку.
Поэтому, когда вы открываете этот тип файла, вы можете открыть его в виде файла класса, и вы можете увидеть конкретное содержимое внутри.
Например, вы можете посмотреть этот файл:
lombok.core.handlers.LoggingFramework
Вы обнаружите, что вы похожи на перечисление, записывая множество реализаций журнала:
При этом журнал, который необходимо создать для каждой аннотации, жестко запрограммирован. Именно из-за этого Lombok знает, какую аннотацию журнала вы используете и какой журнал должен быть сгенерирован для вас.
Например, log4j выглядит так:
private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(TargetType.class);
Это также соответствует нашему предыдущему файлу класса:
А SLF4J такой:
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(TargetType.class);
Второе, на что нужно обратить внимание, это найти вход:
В этом месте загружается точка входа для этих файлов классов, основанная на механизме Java SPI:
В классе AnnotationProcessorHider есть две линии статических внутренних классов, рассмотрим один из них, AnnotationProcessor, который унаследован от абстрактного класса AbstractProcessor:
javax.annotation.processing.AbstractProcessor
Этот абстрактный класс является записью в записи, ядром в ядре.
В этой записи инициализируется загрузчик классов ShadowClassLoader:
Что он делает, так это загружает файлы классов, помеченные как SCL.lombok.
Тогда откуда мне знать, что Lombok основан на аннотациях времени компиляции?
На самом деле это дело написано в двух прочитанных мною книгах.У меня смутное впечатление.Когда писал статью,вывернул и перечитал.
Первая — это глава 10: Компиляция и оптимизация внешнего интерфейса четвертой части книги «Углубленное понимание виртуальной машины Java (третье издание)».
В нем есть специальный раздел, рассказывающий о аннотациях плагинов:
Основной рабочий сайт Ломбока находится в процессе компиляции javac.
На странице 361 книги упоминаются несколько этапов процесса компиляции.
Исходя из общей структуры кода Java, процесс компиляции можно условно разделить на процесс подготовки и три процесса обработки:
-
1. Процесс подготовки: Инициализируйте подключаемый модуль обработки аннотаций.
-
2. Процесс разбора и заполнения таблицы символов, в том числе:
- Лексический и грамматический анализ. Преобразуйте поток символов исходного кода в набор токенов, чтобы построить абстрактное синтаксическое дерево.
- Заполните таблицу символов. Генерирует адреса символов и информацию о символах.
-
3. Процесс обработки аннотаций подключаемым процессором аннотаций. На этапе выполнения подключаемого процессора аннотаций в настоящей боевой части этой главы будет разработан подключаемый процессор аннотаций, влияющий на поведение Javac при компиляции.
-
4. Процесс анализа и генерации байт-кода, включая:
- Проверка вызова. Проверьте статическую информацию грамматики.
- Анализ потока данных и потока управления. Проверьте динамический процесс работы программы.
- Распаковать синтаксический сахар. Восстановите синтаксический сахар, упрощающий написание кода, в исходную форму. (Синтаксический сахар в java включает дженерики, параметры переменной длины, автоматическую упаковку и распаковку, цикл обхода foreach и т. д. Эти синтаксисы не поддерживаются средой выполнения JVM, поэтому их необходимо восстанавливать на этапе компиляции.)
- Генерация байткода. Преобразуйте информацию, сгенерированную на предыдущих шагах, в байт-код.
Если процесс компиляции javac — это рабочий сайт Ломбока, то «процесс обработки аннотаций подключаемого процессора аннотаций» — это его рабочее место.
В книге также упоминается, как работает Ломбок:
Вторая книга «Углубленное понимание байт-кода JVM» в главе 8 также подробно описывает принцип обработки аннотаций подключаемых модулей, в котором также упоминается Lombok:
В итоге я нарисовал вот такую схему:
Если вы читали описания на первых десятках или около того страниц книги, то картина будет более ясной.
Короче говоря, основной принцип Lombok — это волшебная модификация файлов классов во время компиляции, которая генерирует для вас много кода.
Об этом также упоминал автор:
невидимый исходный код, невидимый исходный код.
Невидимое здесь относится к невидимому в java-файле, а в class-файле его все равно некуда спрятать.
Если вы заинтересованы в более глубоком понимании его принципов, вы можете обратиться к двум упомянутым ранее книгам, в которых есть практические разработки.
Я не буду его писать, одна из причин, потому что порог действительно высок, и он отрывистый и сложный для понимания. Другая причина в том, что это не потому, что я ленив.
Эта статья размещена в личном блоге, приглашаю всех в игру: