«1. Обзор
В этой быстрой статье мы рассмотрим одну из наиболее распространенных проблем безопасности в мире JVM — подделку журналов. Мы также покажем пример техники, которая может защитить нас от этой проблемы безопасности.
2. Что такое подделка логов?
По данным OWASP, подделка логов — одна из самых распространенных техник атак.
Уязвимости подделки журнала возникают, когда данные поступают в приложение из ненадежного источника или данные записываются в файл журнала приложения/системы каким-либо внешним объектом.
В соответствии с рекомендациями OWASP подделка или внедрение журнала — это метод записи непроверенного пользовательского ввода в файлы журнала, который позволяет злоумышленнику подделывать записи журнала или внедрять в журналы вредоносное содержимое.
Проще говоря, путем подделки журнала злоумышленник пытается добавить/изменить содержимое записи, исследуя лазейки безопасности в приложении.
3. Пример
Рассмотрим пример, когда пользователь отправляет запрос на оплату из Интернета. На уровне приложения после обработки этого запроса будет зарегистрирована одна запись с суммой:
private final Logger logger
= LoggerFactory.getLogger(LogForgingDemo.class);
public void addLog( String amount ) {
logger.info( "Amount credited = {}" , amount );
}
public static void main( String[] args ) {
LogForgingDemo demo = new LogForgingDemo();
demo.addLog( "300" );
}
Если мы посмотрим на консоль, то увидим что-то вроде этого:
web - 2017-04-12 17:45:29,978 [main]
INFO com.baeldung.logforging.LogForgingDemo - Amount credited = 300
Теперь предположим, что Злоумышленник предоставляет ввод как «\\n\\nweb — 2017-04-12 17:47:08,957 [main] INFO Сумма успешно отменена», тогда журнал будет:
web - 2017-04-12 17:52:14,124 [main] INFO com.baeldung.logforging.
LogForgingDemo - Amount credited = 300
web - 2017-04-12 17:47:08,957 [main] INFO Amount reversed successfully
Злоумышленник намеренно смог создать поддельную запись в журнале приложений, которая исказила значение журналов и в будущем запутала любые действия типа аудита. В этом суть ковки бревен.
4. Предотвращение
Самое очевидное решение — не записывать данные пользователя в лог-файлы.
Но это может быть невозможно во всех случаях, поскольку данные, предоставляемые пользователем, необходимы для отладки или аудита активности приложения в будущем.
Мы должны использовать какую-то другую альтернативу для решения такого сценария.
4.1. Внедрение проверки
Одно из самых простых решений — всегда проверять входные данные перед записью в журнал. Одна из проблем с этим подходом заключается в том, что нам придется проверять множество данных во время выполнения, что повлияет на общую производительность системы.
Кроме того, если проверка не пройдена, данные не будут зарегистрированы и будут потеряны навсегда, что часто является неприемлемым сценарием.
4.2. Ведение журнала базы данных
Другим вариантом является запись данных в базу данных. Это более безопасно, чем другой подход, поскольку «\\n» или новая строка ничего не значат в этом контексте. Однако это вызовет еще одну проблему с производительностью, поскольку для регистрации пользовательских данных будет использоваться огромное количество подключений к базе данных.
Более того, этот метод создает еще одну уязвимость в системе безопасности, а именно SQL Injection. Чтобы справиться с этим, мы могли бы в конечном итоге написать много дополнительных строк кода.
4.3. ESAPI
Использование ESAPI является наиболее распространенным и рекомендуемым методом в этом контексте. Здесь все пользовательские данные кодируются перед записью в журналы. ESAPI — это API с открытым исходным кодом, доступный в OWASP:
<dependency>
<groupId>org.owasp.esapi</groupId>
<artifactId>esapi</artifactId>
<version>2.2.2.0</version>
</dependency>
Он доступен в центральном репозитории Maven.
Мы можем закодировать данные, используя интерфейс кодировщика ESAPI:
public String encode(String message) {
message = message.replace( '\n' , '_' ).replace( '\r' , '_' )
.replace( '\t' , '_' );
message = ESAPI.encoder().encodeForHTML( message );
return message;
}
Здесь мы создали один метод-оболочку, который заменяет все символы возврата каретки и перевода строки символами подчеркивания и кодирует измененное сообщение.
В предыдущем примере, если мы кодируем сообщение с помощью этой функции-оболочки, лог должен выглядеть примерно так:
web - 2017-04-12 18:15:58,528 [main] INFO com.baeldung.logforging.
LogForgingDemo - Amount credited = 300
__web - 2017-04-12 17:47:08,957 [main] INFO Amount reversed successfully
Здесь фрагмент поврежденной строки закодирован и может быть легко идентифицирован.
Важно отметить, что для использования ESAPI нам необходимо включить файл ESAPI.properties в путь к классам, иначе ESAPI API выдаст исключение во время выполнения. Это доступно здесь.
5. Заключение
В этом кратком руководстве мы узнали о подделке журналов и методах преодоления этой проблемы безопасности.
Как всегда, полный исходный код доступен на GitHub.