Важные советы backend-разработчику: защити себя от нежелательных проблем
Чем больше у backend-разработчика знаний в своей области, тем лучшим специалистом он является. Но опыт показывает: самые классные программисты подобны Сократу, который не стеснялся заявлять во всеуслышание «scio me nihil scire», что в переводе на общенародный — «я знаю, что ничего не знаю». Сомневаясь во всём и вся, вы никогда не упустите из виду то, что многие считают «банальным» и «общеизвестным», а потому легко избежите проблем, которые возникают у слишком уверенных себе.
Привет, Хабр! Меня зовут Филипп, и ощутимую часть своей сознательной жизни я работаю бэкенд-разработчиком. За годы, которые я посвятил своей карьере, я успел столкнуться со множеством проектов различной сложности. Среди них были как успешные, так и те, что были весьма перспективными поначалу, но в итоге бесславно завершили своё существование. Само собой, к провалу могут привести совершенно разные причины. Однако, я не раз был свидетелем того, как проекты, имеющие неплохой потенциал развития, погибали из-за каких-то незначительных на первый взгляд ошибок и недоработок. Иными словами, истинная причина провала ĸрылась не в идее, а в деталях, которым нужно было уделить должное внимание и немного времени.
В этой статье я хочу поделиться своим опытом и проанализировать, какие именно проблемы и сложности подстерегают разработчика в области бэкенда веб-приложений, и почему эти проблемы способны вызвать серьёзные трудности как у компании, так и у самого специалиста. Я рассмотрю некоторые ключевые моменты, которые, на мой взгляд, увы, очень часто упускают из виду, и распишу, как эти препятствия можно эффективно преодолеть. Уверен, это поможет минимизировать риски и значительно повысить шансы вашего проекта на успех.
Начинаем делать проект. Используя библиотеку, проверяем её лицензию
Вы только начинаете делать бекенд приложения или веб-проекта, а вас уже подстерегают проблемы. Не вы первый, не вы последний: они попортили кровь и нервы уже многим разработчикам и до вас. Одна из них кроется в выборе библиотек, используемых в проекте, а именно в проверке их лицензий. В своей предыдущей статье, посвященной созданию опенсорс-проектов, я уже поднимал этот нешуточный вопрос, который настолько важен, что должен возникать в числе первых, особенно если дело касается коммерческих разработок. Для меня удивительно, что он обсуждается довольно редко, а некоторые разработчики и вовсе не задумываются о том, что используемые ими сторонние решения могут привести к судебным разбирательствам и большим проблемам у компании, в которой они работают.
Не верите? Тогда представьте такую ситуацию: разработчик небольшой компании включает в коммерческий веб-продукт библиотеку, распространяемую под лицензией GNU Affero General Public License (AGPL). Если вы помните, будучи copyleft-лицензией, AGPL требует, чтобы любое программное обеспечение, использующее код выпущенный под ней, распространялось на тех же условиях. Это значит, весь код вашего веб-приложения, включая уникальные наработки, должен быть открыт и доступен для свободного использования и модификации. Напоминаю, что продукт из нашего примера — коммерческий, а потому доступность каждому его исходников может серьёзно подорвать конкурентное преимущество и бизнес-модель компании.
Большие проблемы могут ждать и проекты, использующие библиотеки с лицензиями, прямо запрещающими их применение в коммерческих целях. Но не лучше ситуация, если лицензии нет вообще: её отсутствие представляет собой даже не меньшую проблему, поскольку любой код по умолчанию защищён авторским правом. Лицензии предоставляют права другим пользователям на использование кода строго на опредёленных условиях, и если лицензии нет, то нет и юридических прав использовать этот код, даже если он находится в открытом доступе.
Справедливости ради отмечу, что проблемы, связанные с лицензированием, могут настичь вас не везде: этот вопрос особенно актуален только для тех стран, что подписали международные соглашения по авторским правам. Например, Бернская конвенция по авторскому праву, которая является одним из основных международных договоров в этой области, на данный момент насчитывает около 180 стран-участниц. Следовательно, использование кода без явного на то разрешения, будет означать нарушение авторских прав и может повлечь за собой судебные тяжбы во многих местах нашей планеты. Но из этого совсем не должно следовать, что прямо сейчас нужно ехать куда-нибудь в страну X только лишь для того, чтобы спокойно нарушать все писанные и неписанные правила. Давайте уважать друг друга, и если кто-то хочет, чтобы его разработка не была использована в каких-то определённых целях, лучше это не делать чисто с человеческой точки зрения.
Как вы можете заметить, вопросы, касающиеся лицензирования и авторского права непросты, и чтобы заранее обезопасить и себя и компанию, в которой вы работаете, лучше прямо сейчас проверить, какими лицензиями обладают используемые вами библиотеки и программное обеспечение. В случае библиотек это сделать не так уж сложно, для любых современных пакетных менеджеров уже есть готовые инструменты. Например, в PHP composer это делается командой composer licenses, в Python pip можно это сделать через pip-licenses, а для Golang эту информацию можно получить через go-licenses.
И не забывайте вызывать эти команды, когда вы обновляете зависимости (а лучше даже автоматизируйте эти проверки), потому что лицензия подключаемой библиотеки может и измениться в новых её редакциях.
Не храните секреты в коде приложения
Следующий совет может показаться не менее очевидным, но менее важным он от этого не становится. Надо запомнить раз и навсегда: в исходном коде не должно быть никакой конфиденциальной или секретной информации, утечка которой может вам навредить. Множество случаев показывает, что злоумышленники могут получить к ней доступ, и в ряде сценариев это приводит к финансовым потерям и другим серьёзным проблемам. К категории чувствительной информации, которую ни в коем случае не следует хранить в коде, относятся:
ключи доступа и секреты API, которые используются для доступа к внешним или внутренним сервисам;
пароли и учетные данные, включая пароли к базам данных, системам администрирования и т.д.;
любые ключи шифрования, которые тоже должны оставаться вне исходного кода;
конфигурационные файлы, содержащие чувствительные данные;
девичья фамилия матери, кличка домашнего животного и прочие ответы на секретные вопросы.
Вместо сохранения такой информации прямо в коде проекта, вы можете использовать переменные окружения (environment variables). Ну, а для более серьезных систем существуют мощные и безопасные хранилища секретов по типу HashiCorp Vault. Кроме всего вышеперечисленного, полезными могут оказаться AWS Secrets Manager или GitHub secrets. Но в любом случае, выбор инструмента для хранения секретов будет зависеть от многих факторов, таких как тип и размер проекта, опыт команды, а также стек используемых технологий.
Кстати, если вам кажется, что проблема наличия чувствительной информации в коде приложений не так уж серьёзна, обращу ваше внимание на статистику. За один только 2022 году GitHub выявил более 1,7 миллионов потенциальных секретов, раскрытых в общедоступных репозиториях. А сколько же таких данных может быть в коде закрытых проектов, разработчики которых даже не задумываются о потенциальных утечках до их возникновения?
Проверьте свой проект прямо сейчас
Если вы уже успели создать свой проект, но только теперь задумались о том, что, возможно, и храните какие-нибудь секреты в коде, решение есть. Вы, конечно, можете проверить всё вручную, но это, скорее всего, потребует уйму времени и усилий. Очевидно, что это как раз тот случай, когда автоматизация — друг человека, и вам не помешают такие инструменты, как:
TruffleHog — инструмент поиска секретов в Git-репозиториях, сканирующий commit history на наличие ключей API и других секретных данных.
GitLeaks — инструмент для обнаружения жестко закодированных секретов, таких как пароли, ключи API и токены, в git-репозиториях.
GitGuardian — приложение, которое работает в вашей локальной среде или в среде CI и помогает вам обнаруживать свыше 350 типов секретов, а также другие потенциальные уязвимости безопасности или нарушения политики, влияющие на вашу кодовую базу.
Решение от GitHub, которое тоже предлагает функцию сканирования кода на наличие секретных данных GitHub Advanced Security. Secret Scanning автоматически сканирует репозитории на наличие известных типов секретов (пароли, ключи API, токены доступа и др.) и может прислать вам уведомление, если такой секрет был найден.
Разумеется, вышеназванные разработки — далеко не единственные представленные на рынке: взять хотя бы те же известные SonarQube или Checkmarx. Эти, и многие другие продукты, предлагают как платные, так и бесплатные решения, подходящие для различных потребностей и бюджетов. Но главная цель данной статьи — не в том, чтобы рассказать о многообразии инструментов по решению проблем с хранением конфиденциальной информации, а в указании на существование этих проблем (и возможных способов их решения). Если вы осознали наличие проблемы — считайте, что полдела сделано. Теперь главное — уделить ей достаточное время и принять соответствующие меры, а какие вы для этой цели будете использовать инструменты, дело десятое.
Закрыт ли доступ к тестовой версии вашей разработки?
Итак, мы разобрались с лицензиями и поняли, почему не стоит хранить секреты в коде. Что ещё может пойти не так? Например, доступы. В веб-разработке довольно распространена практика наличия сразу нескольких версий проекта: для разработчиков (dev), предварительной (staging), рабочей (production) и многих других. Ох, как же часто я сталкивался с ситуацией, когда dev/qa и staging версии сайта или веб-проекта были доступны через интернет любому пользователю. Шутка ли, но порой тестовые версии даже индексируются поисковиками лучше, чем основные. Но вот продукту от этого обычно только хуже.
Главная проблема здесь в том, что тестовые версии могут содержать ошибки, а также уже упомянутую выше секретную или тестовую информацию, которая иногда может быть компрометирующей. Плюс к этому стоит добавить, что бета-версии, как правило, могут быть более уязвимы ко взломам, чем финальная production версия. А это значит, что их доступность увеличивает риск того, что злоумышленник может получить доступ к чувствительным данным, внутреннему коду или даже к самому серверу. К слову, это актуально и в случаях, если вы разрабатываете backend, для, скажем, мобильного приложения, поскольку доступ любых посторонних лиц к тестовым версиям API может быть крайне опасен.
В дополнение к рискам безопасности, важно помнить и то, что наличие дублирующихся страниц веб-сайта может негативно сказаться на его позициях в поисковой выдаче, поскольку поисковые системы, такие как Google, могут воспринимать такие дубликаты как нежелательный контент. А это уже может привести и к тому, что оригинальные страницы вашего проекта будут ранжироваться ниже, а в некоторых случаях и вовсе будут исключены из индексации.
Что делать? С самого начала вам нужна какая-то тактика!
Не экономьте на доменах — если нужна тестовая версия доступная по Сети, купите отдельный домен специально под неё. Это простой, но максимально эффективный способ уменьшить риски безопасности. Связано это с тем, что при поиске уязвимых мест взломщики будут в первую очередь проверять именно поддомены вашего проекта. А это значит, что размещение тестовой версии в открытом доступе на любом поддомене основного ресурса станет для них лучшим подарком, который они примут с большим удовольствием.
Ограничьте доступ к любым тестовым версиям: убедитесь, что dev, qa, staging и другие версии сайта, кроме финальной, нельзя открыть просто так. Необходимо произвести такую настройку, чтобы они были доступны, например, только через VPN. Таким образом, вы снизите вероятность несанкционированного доступа к системе, даже если тестовый домен каким-то образом стал доступен злоумышленникам.
Защитите тестовые версии от индексации. Даже если тестовые версии вашего проекта доступны только через VPN и находятся на отдельных секретных доменах, их следует защитить от индексации поисковиками с помощью файла robots.txt или метатегов noindex. Это очень важное действие, поскольку иногда поисковые системы могут находить и индексировать эти страницы довольно неожиданными способами.
Скрываем реальный IP адрес, задраиваем/закрываем порты
Существуют и правила безопасности, которые знают и помнят далеко не все разработчики, хотя они буквально написаны кровью нервных клеток специалистов, разгребавших хоть когда-то негативные последствия их отсутствия. Одно из таких правил — обязательное сокрытие реального IP-адреса вашего проекта. Если по доменному имени можно определить IP-адреса серверов, это может привести к таким проблемам, как:
DDoS-атаки. Зная реальный IP-адрес вашего проекта, недоброжелатели могут атаковать сервер, на котором он размещён. Например возможна так называемая DNS Reflection Amplification атака, когда злоумышленник отправляет запрос на поиск DNS, заменяя при этом IP-адрес источника на адрес жертвы. С помощью этого нехитрого действия, канал сервера-жертвы забивается огромным объемом ответов от публичных DNS-серверов, при этом атакуемый сервис становится недоступен для его пользователей, а владелец ресурса несёт убытки.
Выявление потенциальных уязвимостей. По айпи вычисляют не только школьники с двача, но и серьёзные хакеры: сканируя открытые порты и исследуя доступное по сети ПО, они могут найти слабое место и атаковать его. От ошибок не застрахован никто. Так, например, MongoDB, одна из самых популярных баз данных с открытым исходным кодом, не один раз была причиной больших утечек чувствительной информации из-за неправильной её настройки. А ведь многих проблем можно было бы избежать, просто спрятав реальный IP-адрес!
Спрятав реальный IP-адрес сервера, вы сразу затрудните задачу потенциальным атакующим. В этом вопросе могут оказаться весьма полезными CDN (сеть доставки контента) или сервисы защиты от DDoS-атак. Например, есть такое популярное и при этом бесплатное решение, как CloudFlare, которое сочетает в себе сразу и возможности CDN, и защиту от DDoS. Можно использовать Imperva (бывшая Incapsula), предлагающую аналогичные функции, или, например, Qrator, специализирующийся на защите веб-приложений как Web Application Firewall, но это уже будет стоить денег.
Хотя эти инструменты могут эффективно помочь в обеспечении безопасности, есть некоторые нюансы, которые тоже стоит помнить:
Существует риск утечки IP через почтовые заголовки. Если вы используете ваш основной сервер в качестве почтового, реальный IP-адрес может быть раскрыт в заголовках электронных писем, и все ваши старания полетят коту под хвост.
С помощью ресурсов вроде DNS History или Whois Request, можно просмотреть историю IP-адресов, ассоциированных с доменом. Если реальный IP-адрес когда-либо был связан с рабочим доменом, его следует изменить.
Будьте особенно осторожны при использовании DDoS-защиты для доменов, применяемых в качестве API-эндпоинтов. Системы защиты иногда могут вводить проверку пользователя, подменяя ваш json/xml на HTML код, что может привести к сбоям в работе клиентской части.
Не забывайте, что отправляя запросы со своего сервера на API сторонних ресурсов, вы также можете раскрыть его IP. Для того, чтобы избежать этого недоразумения, вы можете использовать proxy-серверы, ведь их изменить будет гораздо проще, чем разгребать последствия атаки.
Имейте в виду, что сокрытие реального IP-адреса проекта — не панацея, и крайне важно не забывать закрывать порты используемого ПО от внешней сети, если это конечно возможно в рамках вашей системы. Существует и практика смены стандартных портов, но эта тема не так однозначна. Многие эксперты справедливо могут заметить, что таким образом вы просто усложните себе жизнь, не получив при этом больших преимуществ. Во многих случаях предпочтительнее будет и вовсе настроить доступ к программному обеспечению через unix-сокет вместо сетевых TCP-соединений (актуально для Unix-подобных операционных систем), но это возможно, только если взаимодействие вашего проекта с этим ПО осуществляется на одном сервере. Так вы убьёте сразу двух зайцев: обеспечите более высокую скорость взаимодействия вашего проекта с используемыми сторонними программами и повысите безопасность, ведь порт, который, возможно, усердно ищет злоумышленник, вам не нужен и уже закрыт.
Если же СУБД, или какой-нибудь другой внутренний сервис находится на отдельном сервере, важно настроить доступ к нему только с определённых IP-адресов, которые вы при этом должны тщательно контролировать. Это поможет предотвратить несанкционированный доступ к критически важным системам, обеспечить дополнительный уровень безопасности и минимизировать риски внешних атак и утечек данных.
Не забывайте обновлять зависимости проекта и используемое ПО
Последний совет, который я хочу дать в рамках данной статьи, ещё проще, а потому упускается из виду ещё чаще: своевременно обновляйте зависимости вашего проекта и ПО на сервере. Устаревший и уязвимый код — мечта злоумышленников, которые найдут в нём уязвимость в два счёта. Для получения свежих обновлений вам даже необязательно осуществлять процесс вручную: есть множество способов автоматизации. Например, инструменты управления зависимостями, такие как Dependabot в GitHub, который автоматически обнаруживает устаревшие или уязвимые зависимости и предлагает актуальные обновления.
Автоматизировать стоит и обновление сертификатов безопасности. Возможно, вы использовали или используете сертификаты от Let’s Encrypt, а автоматизировать их обновление совсем не сложно с помощью Certbot. Устаревание сертификатов — боль хуже зубной, а автоматизация их обновления — задача на пять минут. Выбирайте!
То же касается и остального серверного ПО: если вы работаете с Linux, для многих его дистрибутивов, основанных на Debian/Ubuntu, с задачей автоматизации обновлений легко справится Unattended upgrades. Данная функция позволяет автоматически устанавливать обновления безопасности и не только их — всё зависит от того, какие настройки вы решите использовать. Ну, а для совсем серьезных проектов с зоопарком из серверов созданы удобные решения, такие как Ansible, Chef, Puppet или Salt.
Заключение
Советы, которые я дал в данной статье, покрывают далеко не весь спектр того, о чём нужно помнить backend-разработчику. Я решил рассказать лишь о тех вещах, которые крайне важны, но говорят о которых при этом не так часто, как например о защите от SQL-инъекций или от CSRF атаках.
Дополнительно, для более глубокого понимания безопасности веб-приложений, я бы порекомендовал обратить внимание на OWASP Foundation — некоммерческую организацию, предоставляющую ценную информацию в этой области. Например, на веб-сайте этой организации размещён документ OWASP Top Ten, включающий в себя полезный каждому backend-разработчику список из 10 наиболее распространённых и критически важных рисков безопасности веб-приложений. Кроме того, на этом сайте можно найти сведения и о менее известных, но не менее опасных атаках.
Уверен, что сообщество разработчиков должно быть не только компетентным, но и поддерживающим обмен знаниями и опытом, поэтому буду благодарен всем, кто поделитcя в комментариях своими наблюдениями и замечаниями, важными для всех, кто работает в сфере backend-разработки!