Рубрики
Без рубрики

Исключения Java и как их безопасно регистрировать

Как консультант по безопасности, я провожу оценки в самых разных приложениях. На протяжении всего т… Помеченный Java, ведение журнала.

Как консультант по безопасности, я провожу оценки в самых разных приложениях.

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

Ведение журнала и мониторинг часто упускаются из виду, и из-за возросших угроз для веб-приложений они были добавлены в OWASP Top 10 как новая проблема номер десять под названием ” Недостаточное ведение журнала и мониторинг/| .”

Так в чем же здесь проблема? Что ж, давайте взглянем.

Журналы? Кому Нужны Журналы?

Для начала, зачем мы вообще используем ведение журнала? Какой в этом смысл?

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

Как вы узнаете, что кто-то запускает сканер уязвимостей против вашего приложения?

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

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

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

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

Отсутствие этой информации чрезвычайно затрудняет оценку того, кто что сделал, когда и в какой степени был получен доступ.

Создайте стратегию ведения журнала и следуйте ей

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

Я предполагаю, что это может быть стратегией, но можем ли мы добиться большего? Я думаю, мы сможем.

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

Это позволяет легко обмениваться конфигурациями, такими как форматы сообщений, и использовать согласованные шаблоны ведения журнала.

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

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

Все современные платформы ведения журнала поддерживают этот тип информации “из коробки”.

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

Протоколируйте полную трассировку стека

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

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

public Customer findCustomerByName(String customerName) {
  try {
    Customer c = customerService.findByName(customerName);
    return c;
  } catch (Exception ex) {
    LOG.error("Exception looking up customer by name: " + ex.getMessage());
  }
}

Теперь в этом примере есть несколько ошибок, но давайте просто сосредоточимся на обработке исключения SQLException. Допустим, что в процессе производства вы просматриваете журналы и видите это:

2018-03-02 09:29:47.287 ERROR 5166 --- [nio-8090-exec-1] com.scalyr.controllers.DemoController    : org.hibernate.exception.SQLGrammarException: error executing work

Это ни о чем тебе не говорит. Что вызвало исключение SQLGrammarException?

Все классы logger имеют перегрузку, которая принимает объект, который можно выбросить, и будет обрабатывать построение и запись трассировки стека.

Слегка изменив код, мы можем получить более четкое представление о том, что происходит:

public Customer findCustomerByName(String customerName) {
  try {
    Customer c = customerService.findByName(customerName);
    return c;
  } catch (Exception ex) {
    LOG.error("Exception looking up customer by name: " + ex.getMessage(), ex);
  }
  return null;
}

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

2018-03-02 09:33:11.341 ERROR 5188 --- [nio-8090-exec-1] com.scalyr.controllers.DemoController    : org.hibernate.exception.SQLGrammarException: error executing work

org.hibernate.exception.SQLGrammarException: error executing work
    at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:63) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
    at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:109) ~[hibernate-core-5.0.12.Final.jar:5.0.12.Final]
  ... omitted
  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.15.jar:8.5.15]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_144]
Caused by: java.sql.SQLSyntaxErrorException: malformed string: 'Acme''
    at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source) ~[hsqldb-2.4.0.jar:2.4.0]
    at org.hsqldb.jdbc.JDBCUtil.sqlException(Unknown Source) ~[hsqldb-2.4.0.jar:2.4.0]
    at org.hsqldb.jdbc.JDBCStatement.fetchResult(Unknown Source) ~[hsqldb-2.4.0.jar:2.4.0]
    at org.hsqldb.jdbc.JDBCStatement.executeQuery(Unknown Source) ~[hsqldb-2.4.0.jar:2.4.0]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_144]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_144]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_144]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_144]
    ... 105 common frames omitted
Caused by: org.hsqldb.HsqlException: malformed string: 'Acme''
    at org.hsqldb.error.Error.error(Unknown Source) ~[hsqldb-2.4.0.jar:2.4.0]
    at org.hsqldb.error.Error.error(Unknown Source) ~[hsqldb-2.4.0.jar:2.4.0]
    at org.hsqldb.ParserBase.read(Unknown Source) ~[hsqldb-2.4.0.jar:2.4.0]
    at org.hsqldb.ParserDQL.XreadPredicateRightPart(Unknown Source) ~[hsqldb-2.4.0.jar:2.4.0]
    at org.hsqldb.ParserDQL.XreadBooleanPrimaryOrNull(Unknown Source) ~[hsqldb-2.4.0.jar:2.4.0] 
    ... 122 common frames omitted

Это изменение кода, которое мы применили, привело к протоколированию полной трассировки стека, что явно показывает здесь какую-то гнусную деятельность (или толстые пальцы …). Кто-то попытался найти клиента с именем Acme, и это нарушило вашу инструкцию SQL.

Это исключение является явным признаком SQL-инъекции и может быть легко пропущено, если кто-то проанализирует журналы и увидит только исходное сообщение.

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

Регистрируйте Все Исключения Java

“Проглатывание” исключений – еще одна слишком распространенная проблема, которую я вижу.

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

Следующий пример иллюстрирует эту проблему:

public Customer findCustomerByName(String customerName) {
  try {
    Customer c = customerService.findByName(customerName);
    return c;
  } catch (Exception ex) {
    // todo: Log using the new logging strategy..
  }
  return null;
}

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

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

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

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

Не возвращайте исключения пользователю

При выполнении оценки безопасности любого рода любая информация, которую вы можете узнать о приложении или его среде, потенциально полезна.

Кажущееся безобидным сообщение об ошибке может быть именно тем, что нужно консультанту (или злоумышленнику).

Они могут найти один эксплойт, который может работать против вашей системы или значительно снизить полезную нагрузку, необходимую для тестирования SQL-инъекции, если сообщение об ошибке раскрывает что-то об используемой системе баз данных.

Также обычной практикой является просто возврат сообщения об исключении пользователю с помощью какой-либо обработки ошибок.

Я часто сталкиваюсь с этим при тестировании систем аутентификации, как показано на следующем скриншоте:

Код, который обрабатывает это, может делать что-то вроде этого:

User findByUsername(String userName) throws UserNameNotFoundException {
  EntityManager em = entityManagerFactory.createEntityManager();
  return em.createQuery("from User where userName = :userName", User.class)
  .setParameter("userName", userName)
  .getSingleResult();
}

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

public String login(Model model, String username, String password) {
  try {
    // attempt to login user
    userService.login(username, password);
  } catch (Exception ex) {
    model.addAttribute("error", ex.getMessage());
  }
  return "login";

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

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

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

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

Не Регистрируйте Конфиденциальную Информацию

Я упоминал, что журналы могут быть полезны не только для отладки, но и для обеспечения соответствия требованиям, аудита и судебной экспертизы. Поскольку журналы имеют много применений, и у нас есть тенденция просто “регистрировать все”, они могут быть невероятным источником информации.

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

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

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

  • Номера кредитных карт
  • Номера социального страхования
  • Пароли

Но следующие типы информации также не должны записываться в журналы:

  • Идентификаторы сеансов
  • Токены авторизации
  • Личные имена
  • Номера телефонов
  • Информация, от которой пользователь отказался (например, не отслеживать)

Есть еще одна проблема: некоторые юрисдикции не разрешают отслеживать определенную информацию, и это нарушает закон.

Знание требований соответствия приложения и данных, которые оно обрабатывает, чрезвычайно важно.

Не оставайся в Неведении

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

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

Этот пост был написан Кейси Данхэм . Кейси, который недавно открыл свой собственный бизнес в области безопасности, известен своими уникальными подходами ко всем областям безопасности приложений, основанными на его более чем 10-летней карьере профессионального разработчика программного обеспечения. Его сильные стороны включают консультирование по разработке безопасных SDLC; моделирование угроз; обучение разработчиков; и аудит веб-, мобильных и настольных приложений на предмет недостатков безопасности.

Оригинал: “https://dev.to/scalyr/java-exceptions-and-how-to-log-them-securely-1hbm”