Безопасность? Не, не слышал.

2013-11-01

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

Системы контент-менеджмента (CMS)  это основа многих сайтов. Как правило, все они безудержно плохи: с ужасным дизайном, работающие на старых технологиях, практически не задокументированы.

CMS, с которой работаю я, не является исключением.

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

 

Все образцы кода включали в себя валидацию формы на клиентской стороне. Нехороший маячок.

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

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

Я позвонил в тех.поддержку поставщика и получил от них шикарный ответ: «Используйте скрытую форму ввода».

События  это объекты. У объектов есть типы. Списки объектов могут выстраиваться в списки в зависимости от типа. Присвойте объекту тип «unpublished» и скажите списку использовать только объекты типа «published», и все дела. Всё просто, за исключением одной вещи. Вот как происходит присвоение типа:

<input type=”hidden” name=”objectType” value=”unpublished”>

Меня очень взволновал этот вопрос. Скрытая запись не означает, что её нет в интернете. Этот код видим всему миру в исходном HTML. Я знаю, как работают формы, у меня есть информация о том, как отослать событие в систему, в которой есть тип объектов «published». Я попробовал сделать это вручную, и мне это удалось.

В CMS не оказалось никакой возможности подключить серверную сторону. Она просто слепо принимала все данные.

Если вы можете догадаться, какое значение типа объекта необходимо для публикации, вы можете обойти контроль публикации и опубликовать всё, что захотите. За безопасность могло бы отвечать скрытое значение типов опубликованных объектов. Но даже этого нет. Поставщик CMS просто взял и использовал в качестве значения элементарное «published». И этот продукт производится и распространяется, и реальные сайты используют его.

 

Всё было очень плохо, но я даже не подозревал, насколько.

Если пользователи могут опубликовать что-то на сайте, необходимы дополнительные меры безопасности. Например, нужно убедиться в том, что пользователи не могут ввести свой код на вашем сайте. Самое плохое, что может быть  это возможность использовать javascript на стороне пользователя. Если пользователь не ограничен в этом, он может сделать почти всё: изменять поведение сайта, переадресовывать посетителей, заниматься фишингом…

Я провёл эксперимент. Я снова вручную провёл событие к публикации на сайте, но в этот раз я включил небольшой <script>-тэг в одном из полей. И ведь сработало! За кулисами не оказалось никакой скрытой валидации. Код, рекомендуемый поставщиком, просто взял и позволил мне ввести произвольный javascript-код со стороны пользователя на своём сайте.

 

Какого чёрта такое происходит в CMS?

Я решил уведомить об этом поставщика. Провёл небольшое исследование, нашёл несколько практик с вариантами решения проблемы и подал заявку в трэкинг-систему поставщика. Мой коллега, немного знакомый с командой разработки поставщика, помог мне с ними связаться.

Знаете, что мне ответили? «Хм, а что, какие-то пользователи пробовали сделать это?».

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

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

Я мог включить работающие скрипты не только на фронтенде, но и на бэкэнде. Какой простор для мошенничества!

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

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

 

Через час я получил ответ на электронную почту: «Ваша заявка закрыта».

Так и живём.

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

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

Можем ли мы оставаться равнодушными, если подобное происходит в других сферах? В архитектуре, строительстве, инжиниринге… Думаю, нет. 

Почему разработчики это терпят? Почему такие продукты продаются? Почему мы не следим за добросовестностью друг друга?

Если мы профессионалы, слова «профессиональная этика» не должны быть пустым звуком.

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

Перевод: Люся Ширшова. По материалам блога на Medium.com


Читайте также: 

Кодинг в облаке: баловство или шаг вперёд?

Что убивает процесс разработки?

9 главных проблем в работе программиста