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

Десять способов защитить ваши приложения

Наши нападающие продолжают становиться лучше, и мы тоже должны. Вот несколько часто упускаемых из виду способов защиты ваших веб-приложений. С пометкой security, java.

Это сообщение в блоге адаптировано из выступления Джо Катнера на Devoxx 2018 под названием ” 10 Ошибок, Которые Хакеры Хотят, чтобы Вы Совершили .”

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

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

1. Убедитесь, что зависимости обновлены

Каждый год |/OWASP , группа экспертов и исследователей в области безопасности, публикует список распространенных угроз безопасности приложений, на которые следует обратить внимание. Одна из наиболее распространенных проблем, которые они обнаружили, – это использование зависимостей с известными уязвимостями . Когда-то известный CVE публикуется, многие разработчики и разработчики с открытым исходным кодом прилагают сосредоточенные усилия для выпуска исправленных обновлений для популярных фреймворков и библиотек. Но в одном отчете было обнаружено, что более 70% эксплуатируемых приложений связаны с устаревшими зависимостями .

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

С помощью Maven вы можете использовать плагин Maven Versions , который автоматически обновляет ваш pom.xml для использования новейших пакетов. В Ruby команда bundle update |/выполняет нечто подобное. Вы можете включить эти инструменты в свой процесс CI/CD и сразу же выполнить тест с ошибкой, если зависимость устарела, что вынудит вас обновить пакет до того, как ваше приложение сможет быть развернуто.

Более активным подходом может быть включение инструмента, который автоматически отслеживает ваши зависимости для вас, например Снык . Вместо того, чтобы запускать проверку при изменении кода (что может подвергнуть ваше приложение уязвимости в течение нескольких недель или месяцев, если оно обновляется нечасто), Snyk отслеживает ваши зависимости и сравнивает их с известным списком уязвимостей, сопоставленных с зависимостями . Если обнаружена проблема, они предупредят вас с помощью отчета, в котором будет указано, какие зависимости устарели и какая версия содержит исправленное исправление. Snyk также может бесплатно примерить Heroku.

2. Явно объявлять допустимые пользовательские полезные нагрузки

Слишком часто веб-приложения принимают практически все, что пользователь отправляет через форму или API. Например, пользователь может попытаться создать учетную запись с паролем, содержащим более тысячи символов. Когда отправляются многочисленные запросы, подобные этому, возможно, что сервер выйдет из строя из-за интенсивных вычислений, необходимых для их шифрования.

Одним из способов смягчения подобных атак является реализация ограничений на уровне базы данных. Столбцы должны иметь определенный максимальный размер, или ваша модель данных должна отказаться принимать значения NULL . Хотя наложение этих ограничений на базу данных всегда является хорошей идеей, ее можно считать слишком “низкоуровневой”, поскольку некоторые атаки могут быть использованы на более ранних этапах цикла запроса.

Если ваше приложение подключено к Интернету, каждая уязвимость – это всего лишь один curl вызов. В одном примере с библиотекой привязки данных Jackson простая полезная нагрузка JSON смогла выполнить произвольный код, как только запрос был получен сервером.

Предоставляя явный список ожидаемых входных данных , вы можете гарантировать, что ваше приложение работает только с данными, которые, как ему известно, будут поступать, и игнорирует (или вежливо выдает ошибки) все остальное. Если ваше приложение принимает JSON, возможно, как часть API, реализация JSON schemas является отличным способом моделирования приемлемых запросов. Например, если конечная точка принимает два строковых поля с именем FirstName и фамилия и одно целое число с именем возраст , схема JSON для проверки пользовательских запросов может выглядеть следующим образом:

{
  "title": "Person",
  "type": "object",
  "properties": {
    "firstName": {
      "type": "string",
      "description": "The person's first name."
    },
    "lastName": {
      "type": "string",
      "description": "The person's last name."
    },
    "age": {
      "description": "Age in years which must be equal to or greater than zero.",
      "type": "integer",
      "minimum": 1
    }
  }
}

Указав допустимые типы, вы можете предотвратить возникновение непредвиденных проблем, если пользователь решит отправить целые числа для FirstName или отрицательные числа для age .

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

3. Утверждение безопасных регулярных выражений

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

Рассмотрим простой шаблон, подобный этому: (a|aa)+ . Хотя это выглядит безобидно, | (“или”) в сочетании с оператором + может занять катастрофически много времени для сопоставления со строкой, такой как "ааааааааааааааааааааааааааа!" . Злоумышленники могут вызвать атаку типа “отказ в обслуживании” на вашу систему, отправив особенно сложный (но все же технически “действительный”) текст. ( Аналогичная проблема затронула Node.js сообщество несколько лет назад.)

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

$ java -jar target/saferegex.jar "(a|aa)+"

Testing: (a|aa)+
More than 10000 samples found.
***
This expression is vulnerable.
Sample input: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab

4. Предотвращение оскорбительных запросов

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

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

Лучшей реализацией было бы использование библиотеки, которая использует преимущества алгоритма с использованием маркеров . Bucket – одна из таких библиотек. Входящие запросы группируются по различным свойствам в отдельные “сегменты”, и эти сегменты, в свою очередь, могут быть ограничены или полностью занесены в черный список. Классифицируя, какие запросы приемлемы, а какие нет, вы сможете лучше справляться с внезапными всплесками трафика.

5. Выровняйте свой код, чтобы он был безопасным – в первую очередь

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

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

6. Храните учетные данные за пределами вашей кодовой базы

Мы все знаем (надеюсь!) что разглашение вашего личного пароля может стать катастрофической ошибкой. В любом достаточно сложном приложении может быть дюжина различных токенов и паролей для управления: имя пользователя и пароль вашей базы данных, токены для аутентификации в New Relic, DataDog или Redis…

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

Храните свои секреты в переменных среды. Библиотека, подобная дотенв может легко загружать и использовать эти переменные при условии, что они доступны в безопасном месте. Другой вариант – использовать такой продукт, как Hashicorp Vault , который позволяет вашему приложению управлять секретами с помощью настраиваемого интерфейса командной строки.

7. Отклонять HTTP-запросы

Если у вас нет очень специфического варианта использования, вам следует отключить HTTP-соединения с вашим сервером . Соединение HTTPS гарантирует, что данные между клиентом и сервером зашифрованы, тем самым предотвращая атаки “человек посередине”. Большинство основных браузеров по умолчанию используют HTTPS-соединения по умолчанию, а такие сервисы, как Let’s Encrypt , делают получение SSL-сертификата для вашего приложения проще, чем когда-либо.

Если вам нужно поддерживать HTTP локально или между прокси-сервером и вашим веб-сервером, вы можете настроить свой сервер так, чтобы он принимал только клиентов, для которых X-Forwarded-Proto заголовок запроса установлен в https . В зависимости от вашей настройки это также может быть настроено вне вашего кода с помощью конфигурации NGINX или Apache.

8. Включить проверку сертификатов

Иногда вашему приложению может потребоваться позвонить внешнему поставщику услуг. Аналогично приведенному выше предложению, вы должны включить проверку сертификатов для исходящих подключений . Это гарантирует, что связь со сторонними API или службами также защищена через HTTPS. Обратите внимание, что если сторонний веб-сайт имеет неправильно настроенный сертификат, это может привести к ошибкам при попытке подключения вашего приложения. У вас может возникнуть соблазн просто отключить проверку сертификатов, чтобы убедиться, что приложение “просто работает”, но это очень небезопасный шаг, который подвергает риску данные ваших пользователей.

Вы можете использовать библиотеку типа Env KeyStore для облегчения хранения ключей и сертификатов. Подобно putenv, Env KeyStore запрашивает, чтобы вы продолжали устанавливать сертификат PEMbe в переменную среды. Затем вы можете использовать эту ФОРМУ в качестве средства проверки по умолчанию для любых исходящих клиентских запросов. Например:

KeyStore ts = EnvKeyStore.createWithRandomPassword("TRUSTED_CERT").keyStore();

String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(ts);

SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, tmf.getTrustManagers(), new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

String urlStr = "https://ssl.selfsignedwebsite.xyz";
URL url = new URL(urlStr);
HttpsURLConnection con = (HttpsURLConnection)url.openConnection();
con.setDoInput(true);
con.setRequestMethod("GET");
con.getInputStream().close();

9. Регистрируйте и отслеживайте подозрительное поведение

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

  • Успешные и неудачные входы в систему
  • Сброс пароля
  • Изменения в уровнях доступа
  • Сбои авторизации

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

Чтобы отделить эти события от других ошибок, мы рекомендуем предварять ваши инструкции журнала такими фразами, как SECURITY_SUCCESS , SECURITY_FAILURE и SECURITY_AUDIT . Таким образом, вы можете легко отфильтровать определенные категории сбоев авторизации, если возникнет такая необходимость. Имейте в виду, что конфиденциальная информация, такая как идентификаторы сеансов или пароли, не должна регистрироваться, поскольку они будут храниться в открытом виде.

Другая тактика, которую можно использовать, – это добавить систему обнаружения вторжений . У OWASP есть проект под названием App Sensor , который предоставляет платформу для автоматического обнаружения потенциальных атак и реагирования на них. Это работает путем добавления агента в ваше веб-приложение, который отправляет события в вашу внешнюю службу датчиков приложений. App Sensor проанализирует эти события, и, если он определит вредоносное поведение, AppSensor ответит веб-приложению полезной нагрузкой с информацией, определяющей, что происходит. Затем приложение может определить, какие действия следует предпринять.

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

10. Ограничьте свой собственный доступ

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

  • Использование двухфакторной аутентификации везде, где это возможно
  • Блокировка экрана компьютера в любое время, когда вы не находитесь на своей рабочей станции
  • Внедрение уникальных паролей для всех учетных записей и служб, а также использование менеджера паролей

Заключительные мысли

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

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

Будьте в безопасности и снова поделитесь любыми советами по безопасности, которые у вас есть, в комментариях — для Java или любого другого языка!

Оригинал: “https://dev.to/heroku/ten-ways-to-secure-your-applications-48df”