Твой код глазами хакера: 5 советов для разработчиков из Казахстана (и не только)

Публикуем разбор нескольких важных вопросов по безопасности веб-приложений от Кутлымурата Мамбетниязова, старшего эксперта по информационной безопасности (ИБ) в компании BTS Digital.

Планируем рубрику с такими практическими разборами сделать регулярной, чтобы вы могли обмениваться опытом с коллегами. Если Вам есть чем поделиться — пишите на editor@digitalbusiness.kz!

Кто такой Кутлымурат Мамбетниязов?

Мурат ведет блог и канал в Telegram, где делится результатами своих исследований, проверяя open-source системы на наличие уязвимостей. Является старшим экспертом по информационной безопасности в компании BTS Digital.

Разбор примеров и эти пять советов для разработчиков Кутлымурат озвучил в своем выступлении на ежегодной ИТ-конференции BeeTech Conf, которая прошла в Алматы 22 апреля.

Как я стал безопасником

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

Сайт был взломан, как они представились, турецкими хакерами. Тогда я не понимал, зачем кому-то взламывать свежий сайт без финансового оборота. Позже, изучая вопрос, понял, что черным хакерам всегда нужны свежие чужие IP-адреса и сайты, чтобы они могли, не попадая в бан, отправлять спам и фишинговые письма. Или использовать взломанный сайт как прокси-сервер (т.е. пускать весь поток данных через взломанный сайт) для сокрытия следов новых атак.

А это означает, что информационная безопасность важна для всех, в независимости от масштабов проекта.

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

Сегодня есть отдельные специалисты по ИБ для проверки мобильных приложений, веб-приложений, инфраструктуры, сетей, умных устройств, АСУ ТП, облачных решений. Есть даже специалисты социальной инженерии, кто занимается самым уязвимым звеном любой компании — людьми. Они отправляют фишинговые письма для проверки бдительности сотрудников компании, а самые продвинутые могут переодеться в сантехника или электрика и прийти прямо в офис компании, чтобы миновать охрану и сесть за свободный компьютер в офисе.

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

1. Про секретные ключи

Разработка системы означает неминуемое использование разного рода паролей, секретных ключей, подписей. Но речь пойдет про одну из популярных технологий авторизации среди разработчиков — JSON Web Token (JWT). Это — токены, которые используются для авторизации в разных системах. Подробнее можно узнать и поиграть на jwt.io.

JWT токены состоят из 3-х частей, закодированные в base64.

Пример токена:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb25mIjoiQmVlVGVjaCIsInNwZWFrZXIiOiJAbWFuZnJvbWt6IiwiaXNfYWRtaW4iOjF9.Q5iNL4Gu5awCROqEnijqDaJU3eiBEvAusxkchJhhAUY

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

Это означает, что любой, кто знает секретный ключ JWT токенов, с вероятностью 90% захватит контроль над вашим приложением. Конечно, любой подумает, что его ключ никому не доступен или вообще не подозревает, что ключ давно известен всему интернету. Как это происходит?

Попробуем ввести в поисковик: «jwt java example spring boot».

Google выдает 753 тысяч результатов с вариантами реализации JWT токенов на базе Java Spring Boot.

Открываем первую же ссылку и видим следующее:

В данном случае «javainuse» является тем самым секретом, который используется для проверки токенов. Какие шансы, что вы скачаете этот код и забудете поменять секрет?

Проверяем дальше:

Как минимум этот «секрет» уже добрался до репозиториев на Github:

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

Словарь содержит 3502 секретов со всего интернета, и если ваш секрет нашелся в этом словаре, то срочно бегите менять секрет на другой, и чтобы он состоял как минимум из 20 символов. Также нужно понимать, что на каждую среду разработки (dev, stage, prod) должны быть свои разные секреты. Это нужно для того, чтобы хакеры не могли взломать все серверы, если удалось взломать хотя бы один.

2. Про кодогенерацию

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

CRUD (Create, Read, Update, Delete) — объединенное название нескольких операций работы над данными.

Например, таблица в базе данных такого вида:

Превращается в код такого вида (на скриншоте код из Yii2):

Это позволяет искать данные пользователей таким образом:

https://testsite.kz/users/index?UsersSearch[PARAM]=VALUE

Где PARAM — название параметра, а VALUE — необходимое нам значение.

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

Но что будет, если вместо параметра name передать параметр password?

Появится возможность перебирать пароли (или хэш пароля) пользователей посимвольно.

Фреймворкам все равно, на какие поля генерировать фильтры для поиска, и всегда нужно самостоятельно убирать из таких фильтров поля типа password, secret, reset_token и другие с чувствительными данными. Иначе, насколько безопасным не был бы сам фреймворк, это может привести к компрометации системы.

3. Про SQL-инъекции

Существует множество векторов атак на веб-приложения. Один из вариантов — это SQL-инъекция.

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

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

Существуют платформы, которые платят за находку уязвимостей на сайтах крупных компаний. Одна из таких платформ Hackerone. По ссылке 261 случаев находки SQL-инъекций в крупных компаниях.

Неполный список компаний, у которых нашли SQL-инъекцию: Starbucks, Razer, Mail.ru, QIWI, Acronis, Zomato, Uber, OLX, GitLab, IBM и другие.

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

Откуда берутся SQL-инъекции?

Первое, что делают веб-разработчики, изучая какой-либо язык, ищут в поисковике «как написать регистрацию и авторизацию на языке X». Я попробовал сделать так же:

Не выбирая, открыл первые 3 ссылки.

1-я ссылка. Сайт продает курсы по программированию.

Параметр $login без фильтрации попадает в SQL-запрос, что позволяет внедрять свои инструкции, например, вывести пароли пользователей.

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

3-я ссылка. Точно такая же картина

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

Поэтому нельзя верить туториалам и нужно всегда спрашивать совет у разработчика постарше. В ИТ сообщество отзывчивое и всегда поможет с вопросами. Существуют много разных Telegram-чатов или онлайн-сервисов (как Stackoverflow), где код обсуждается тысячами разработчиков.

4. Про фильтры

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

Речь пойдет про функции фильтрации, а именно про фильтрацию e-mail адресов.

Представьте, что вы отправили пять писем на эти адреса:

test@murat.one
test+test1@murat.one
test+qwe@murat.one
test+sdfgdfghdfg@murat.one
test+anything@murat.one

В таком случае все пять писем придут на адрес test@murat.one. Так как по стандарту RFC это все один и тот же адрес, а все, что идет после знака плюс, является категорией письма.

RFC (англ. Request for Comments) — документ из серии пронумерованных информационных документов интернета, содержащих технические спецификации и стандарты, широко применяемые во всемирной сети.

Поэтому если на вашем сайте критично, чтобы 1 человек не мог зарегистрироваться несколько раз, то запретите знак «+» для поля e-mail.

Рассмотрим два варианта стандартных фильтров для Golang и Python.

В языке Golang в пакете net/mail есть функция ParseAddress, которая отвечает за валидацию e-mail: pkg.go.dev/net/mail#ParseAddress

Простой пример кода:

А теперь попробуйте ввести в эту функцию следующие e-mail адреса:

test@murat.one
test+test@murat.one
test{{7*7}}test@murat.one
te'+union+select+1--+g't@murat.one

Вы заметите, что функция считает правильными все эти e-mail адреса. Как так произошло? А потому, что функция соблюдает стандарт RFC, который позволяет использовать почти все символы.

Вот список e-mail адресов из Wikipedia, который кажется неправильным, но на самом деле соответствуют всем стандартам:

Попробуем то же самое сделать для Python. Из пакета email.utils используем функцию parseaddr: docs.python.org/3/library/email.utils.html#email.utils.parseaddr

Получим следующий результат:

То есть все e-mail адреса успешно прошли валидацию, хоть и содержали в себе вредоносный SQL-запрос и HTML-код.

Но и на этом сюрпризы не заканчиваются. Например, для почтовых серверов Gmail точки в адресе не играют никакой роли:

И почты johnsmith@gmail.com, john.smith@gmail.com, jo.hn.smi.th@gmail.com, jo.hns.m.i.t.h@gmail.com и т.д. являются идентичными. Если для вас важно, чтобы люди не регистрировали мультиаккаунты, то следует для Gmail написать отдельный фильтр, который удаляет точки.

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

5. Про отладку

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

Например, в языке программирования PHP для отладки используется функция phpinfo() — www.php.net/manual/en/function.phpinfo.php

Отладка запускается 1 строкой кода:

<?php phpinfo(); ?>

Но доступная всем такая функция:

  • позволяет временно загружать файлы в папку %TMP%
  • позволяет смотреть защищенные cookies
  • выдает информацию по установленными модулям и ОС
  • выдает настоящий IP-адрес сервера

Согласитесь, теперь все это выглядит не так безобидно. Вот пример загрузки файла через phpinfo:

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

В Django, если в конфигурации указан DEBUG=true, то включается режим отладки:
docs.djangoproject.com/en/4.1/ref/settings/#debug

Режим отладки в Django позволяет узнать всю структуру функционала системы, включая адрес админ-панели:

А если интегрировать Django с другой системой, например, с Sentry, то режим отладки может выдать секретный ключ для токенов:

Что позволяет выполнять любые команды в системе из-за особенностей десериализации.

Например, один исследователь заработал $5000 за находку такой ошибки на серверах Facebook.

Вывод, отключаем режим отладки везде, если это не dev-среда. А если это dev-среда, убеждаемся, что она недоступна всем из интернета.

Заключение

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

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

Кроме того, не стоит стесняться обращаться за советами к более опытным коллегам.

 

CRUDКутлымурат МамбетниязовИБJWTBTS Digitalинформационная безопасностьхакеры