Pull to refresh

Немного о защите идентификаторов веб-сессий

Reading time8 min
Views16K
Original author: Eran Hammer
Предлагаем вашему вниманию перевод статьи из блога Eran Hammer — создателя фреймворка hapi.js. На этот раз речь пойдет об обеспечении безопасности идентификаторов сессий.



На Github прозвучал вопрос о том, зачем в Node.js-фреймворке Express к идентификационной cookie сессии добавляется хэш-суффикс? Отличный вопрос.

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

Брутфорс


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

Пароли — это не единственные учетные данные, использующиеся для веб-аутентификации. В наиболее распространенных реализациях используется страница логина, после успешного ввода данных на которой клиенту присваивается cookie-идентификатор сессии. Он служит «токеном предъявителя» — любой, кто «предъявит» этот токен, рассматривается системой в качестве прошедшего аутентификацию пользователя. Использование cookie-идентификатора избавляет от необходимости ввода логина и пароля на каждой странице. Однако теперь, этот id сессии является единственным ключом аутентификации, и любой, кто получит к нему доступ, сможет попасть в систему. В конце концов, cookie — это не более, чем строка символов.

Атаки подборка идентификаторов сессии — это разновидность брутфорс-атак. Вместо того, чтобы пытаться угадать пароль, атакующий подбирает идентификатор сессии. Злоумышленник генерирует идентификаторы сессии и отправляет с их помощью запросы в надежде на то, что какой-то из вариантов совпадет с реальным идентификатором активной сессии. Например, если в веб-приложении идентификаторы генерируются последовательно, то киберпреступник может просто использовать идентификатор собственной сессии и на его основе уже подбирать действующий id (предлагая системе «близлежащие» значения).

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

Нецелесообразность


Прежде всего необходимо сделать так, чтобы идентификаторы сессиий были достаточно длинными и выдавались не последовательно. Тут как с паролями — чем длиннее идентификатор, тем сложнее подобрать «валидный» с помощью перебора. Критически важно еще и генерировать такие id не с помощью предсказуемого алгоритма (например, со счетчиком), поскольку если такая логика присутствует, то атакующему уже даже не надо угадывать идентификаторы — он просто будет их генерировать по алгоритму. Использование для создания достаточно длинных id криптографически безопасного генератора случайных чисел — наилучший вариант. Что значит «достаточно длинных»? Это зависит от природы конкретной системы. Размер должен приводить к нецелесообразности усилий по подбору идентификатора сессии.

Другой способ защититься от угадывания сессионых id заключается в построении целостности токена с помощью добавления хэша или подписи для cookie сессии. В Express промежуточный софт, отвечающий за работу с сессиями, делает это вычисляя хэш для комбинации сессионного id и некого дополнения («секрета»). Поскольку для вычисления хэша в таком случае нужно знать секрет, то злоумышленник не сможет сгенерировать «валидный» идентификатор сессии без необходимости угадывания секрета (в противном случае ему просто предется перебирать хэши). Как и в случае сильных случайных id сессий, размер хэша должен соответствовать требованиям безопасности конкретного приложения. Не забываем, что сессионная cookie — это всего лишь строка символов, которые можно и подобрать.

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

Уровни защиты


Если в нашей системе генерируются сильные случайные идентификаторы сессий, нужен ли нам все равно хэш? Безусловно!

Ключевым принципом безопасности является наслоение. Еще его называют принципом «не класть все яйца в одну корзину». Если полагаться только на один источник безопасности, то в случае, если его удастся взломать, никакой безопасности не останется вообще. К примеру, что будет, если кто-то найдет ошибку в используемом генераторе случайных чисел? Что если затем им удастся взломать эту часть системы, и модифицировать ее? История знает множество примеров успешных атак, организаторы которых проделали именно это — генерировали случайные числа, которые на поверку оказывались совсем не такими случайными (мы писали о подобных уязвимостиях: раз и два).

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

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

Оповещение о проблемах


Важное отличие в подборе паролей и идентификаторов сессий заключается в том, что пароли ассоциированы с учетной записью (например, именем пользователя). Пара имя пользователя-пароль облегчает отслеживание брутфорс атак — увидеть, что кто-то много раз неверно ввел пароль для конкретной учетной записи, довольно легко. Однако, когда дело касается идентификаторов сессий, все не так просто — у сессий есть время действия и они не имеют дополнительного контекста, вроде имени пользователя. Это значит, что идентификатор может быть «невалидным» и в случае ее истечения, и при проведении атаки. Но без дополнительных данных (например, IP-адреса), понять, что на самом деле происходит, довольно трудно.

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

Гигиена безопасности


Аутентификационные данные должны иметь срок действия, поэтому у идентификатора сессии должен быть конечный срок жизни (его конкретная длина зависит от особенностей системы). У сookie есть срок истечения, однако не существует способа проверить его соблюдение. Злоумышленник может установить любое значение параметра экспирации cookie, и сервер никак не сможет об этом узнать. Хорошей практикой здесь является использование временной метки для любых аутентификационных данных — можно просто добавлять суффикс временной метки к случайно сгенерированному id сессии. Однако, чтобы в полной мере доверять таким меткам, нужно убедиться в том, что ее никто не изменял. Для этого и нужны подпись или хэш.

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

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

Аварийная кнопка


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

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

Общее предназначение


Важная функция промежуточного сессионного софта фреймворка Express — это поддержка user-generated идентификаторов сессий. Она позволяет разработчикам развертывать программное обеспечение в существующей среде, где сессионные идентификаторы генерируются некой существующей сущностью, которая может быть реализована на совсем другой платформе. Если не добавлять хэш к сгенерированному пользователем идентификатору сессии, то за построение безопасной системы будет отвечать не эксперт (разработчик конкретного модуля), а пользователь (новый подход к безопасности). Использование хэша — куда более верный подход, чем применение внутреннего генератора идентификаторов сессий.

Нужны ли крокодилы


Добавление хэша к сильному случайному идентификатору сессии — не все, что нужно сделать. Нужно ли запустить в ров с водой еще и крокодилов — зависит от замка. Существует множество уровней защиты сессий, которые можно использовать. К примеру, можно использовать два экземпляра аутентификационных данных, один «долгоживущий» (живет столько же, сколько сама сессия) и «кратковременный» (активный несколько минут или часов). Чтобы обновить последний используется долгоживущий экземпляр, но при этом снижается его распространенность в сети (полезно, когда не используется TLS).

Другой распространенный способ — создание cookie с общей информацией о пользователей (имя, недавно просмотренные элементы и т.п.) в добавок к сессии, впоследствии к хэшу добавляется что-либо из этой cookie — так создается связь между активным состоянием пользователя и аутентификацией. «Имя пользователя» опять возвращается в игру.

Можно пойти дальше и заменить хэширование электронной подписью, а содержащие cookie зашифровать (и вдобавок еще захэшировать или подписать). Количество уровней безопасности должно соответствовать возможным угрозам.

Заключение


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

Кроме того, не следует поддаваться искушению вступить в «академические дебаты» по поводу какой-либо характеристики безопасной системы. Например, вопрос «есть ли статистическое преимущество в хэшировании сильного случайного идентификатора сессии» создает впечатление, будто это единственное, о чем нужно думать. Таким образом дискуссия уходит из реального мира в область абстрактных понятий. Существует множество причин на то, чтобы использовать хэширование в дополнение к усложнению атак перебором.
Tags:
Hubs:
+11
Comments10

Articles

Information

Website
www.ptsecurity.com
Registered
Founded
2002
Employees
1,001–5,000 employees
Location
Россия