🕸 Веб-аутентификация: файлы cookies или токены?

Сравним аутентификацию в веб-приложениях на основе токенов и файлов cookies, чтобы помочь вам выбрать наилучший подход для проекта.

Перевод публикуется с сокращениями, автор оригинальной статьи Chameera Dulanga.

Cookie-Based Authentication

Аутентификация – это процесс обмена учетными данными для идентификации пользователя. При аутентификации на основе cookies уникальный идентификатор (файл cookie) создается на стороне сервера и отправляется в браузер.

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

Чтобы лучше понять, как работают файлы cookie, разобьем этот процесс на 5 частей.

1. Пользователь входит в приложение со своими учетными данными

2. Сервер проверяет учетные данные и создает сеанс в базе данных

Примечание:
Хотя сеанс можно создать в памяти, он не масштабируется.

3. Сервер отправляет файл cookie браузеру, включая его в заголовок Set-Cookie

Файл cookie отправляется в виде пары имя-значение и содержит уникальный идентификатор (id) пользователя.

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

HTTP/2.0 200 OK
Content-Type: text/html
Set-Cookie: <cookie-name>=<cookie-value>
Set-Cookie: <cookie-name>=<cookie-value>; Expires=<date>
Set-Cookie: <cookie-name>=<cookie-value>; Max-Age=<number>
Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain>
Set-Cookie: <cookie-name>=<cookie-value>; Path=<path>
Set-Cookie: <cookie-name>=<cookie-value>; Secure
Set-Cookie: <cookie-name>=<cookie-value>; HttpOnly

[page content]
Примечание:
Вы можете использовать один заголовок Set-Cookieдля установки нескольких атрибутов (Set-Cookie: <cookie-name>=<cookie-value>; Domain=<domain>; Secure; HttpOnly).

4. Браузер сохраняет cookie в хранилище и отправляет его с последующими запросами

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

Найти все сохраненные в браузере файлы cookie можно в хранилище файлов cookie в разделе приложения с помощью инструментов разработчика (devtools).

5. Когда пользователь выйдет из системы, сервер удалит сеанс из базы данных

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

Мы разобрались, как работает аутентификация на основе cookie, теперь рассмотрим фичи, плюсы и минусы этой схемы.

Это полностью автоматизированный процесс

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

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

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

Безопасность

Cookie не имеют надежной защиты от атак, и они в основном уязвимы для атак с использованием межсайтового скриптинга (XSS) и подделки межсайтовых запросов (CSRF).

Мы можем явно изменить заголовки файлов cookie, чтобы защитить их от таких атак.

Например, куки могут быть легко защищены от XSS-атак с помощью атрибута HttpOnly при настройке заголовков:

Set-Cookie: <cookie-name>=<cookie-value>; Secure
Set-Cookie: <cookie-name>=<cookie-value>; HttpOnly

Кроме того, можно использовать атрибут SameSite в заголовке файла cookie для эффективного предотвращения CSRF-атак.

Set-Cookie: <cookie-name>=<cookie-value>; SameSite=Lax

Есть 3 значения, которые можно использовать для атрибута SameSite:

  • SameSite = Lex гарантирует, что браузер не будет отправлять файлы cookie по межсайтовым запросам (это поведение по умолчанию, если атрибут SameSite не определен).
  • SameSite = Strict будет следить за тем, чтобы браузер отправлял cookie только для запросов с того же сайта.
  • SameSite = None позволит отправлять куки как с межсайтовыми, так и с внутрисайтовыми запросами.

Обычно работают в одном домене

Файлы cookie работают только в одном домене, если вы специально их не настроили.

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

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

Не подходит для API

Если вы создаете API для предоставления услуг клиентам, cookie – это не лучший вариант. Если клиент не является браузером, это усложнит работу.

Например, если вы разрабатываете мобильное приложение, наличие файлов cookie усложнит управление файлами по сравнению с токеном.

Могут возникнуть проблемы с масштабируемостью

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

Хотя существуют хорошо зарекомендовавшие себя способы управления масштабируемостью (например, использование для хранения сеансов СУБД наподобие Redis), это все равно добавляет сложности. По мере роста количества пользователей, могут возникнуть проблемы с масштабированием и управлением сеансами.

Подходит для хранения дополнительных данных

Поскольку этот подход поддерживает отдельные сессии для каждого пользователя, мы можем хранить прикрепленные к ним данные.

С помощью файлов cookie и сессий можно хранить дополнительные данные персонализации, контроля доступа и сами сессии – это позволяет использовать их для последующих запросов.

Все эти манипуляции можно провести и с помощью токенов. Например, токены JWT позволяют хранить Claim-объекты. Поскольку это увеличит размер токена, сохранение большего их количества повлияет на нагрузку сети.

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

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

Аутентификация на основе токенов

Этот способ был введен для устранения основанного на куках аутентификации. Особенности подхода – требуется ручная реализация и токены сохраняются на стороне клиента.

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

Стандартные реализации токен-подхода в разы сложнее описанных выше. Например, в OpenID Connect применяется несколько потоков аутентификации для различных сценариев использования. Чтобы лучше понять, как работают токены, разобьем процесс на четыре части и в качестве примера используем JWT (JSON Web Token) – наиболее широко используемый стандарт.

1. Пользователь входит в приложение со своими учетными данными

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

При передаче обычно необходимо использовать шифрование (например, SSL) для защиты канала.

На стороне сервера можно использовать библиотеку NPM (такую как jsonwebtoken) для создания токенов:

// Install
npm install jsonwebtoken
// Usage
var jwt = require('jsonwebtoken');
var token = jwt.sign(
              { data: user}, 
              privateKey, 
              { algorithm: 'RS256'},
              exp: Math.floor(Date.now() / 1000) + (60 * 60),            );

Сгенерированный с помощью jsonwebtoken токен будет выглядеть следующим образом:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Токен состоит из 3 частей: header, payload и signature (header.payload.signature). Они разделены символом ., и вы можете использовать этот сервис для анализа информации.

3. Сохранение токена в хранилище браузера и добавление в запросы с помощью JavaScript

Браузер может хранить этот маркер в локальном хранилище, хранилище сеансов или в хранилище cookies. Затем он будет добавлен в заголовок авторизации и отправлен на сторону сервера для валидации запросов.

Добавление токена в заголовок должно быть реализовано с помощью JavaScript.
Authorization: Bearer <token>

Кроме того, можно использовать функцию jwt.decode() из библиотеки jsonwebtoken для декодирования токена.

4. При выходе пользователя из системы токен вручную удаляется из хранилища

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

Мы разобрались, как работает аутентификация на основе токенов, теперь рассмотрим фичи, плюсы и минусы этой схемы.

Это stateless-механизм

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

Проблемы безопасности

Хотя введением токенов пытаются решить проблемы безопасности аутентификации на основе cookies, полностью от них не избавиться.

Сохраненные в браузере токены могут быть уязвимы для атак XSS, если приложение позволяет внедрять внешние сценарии JavaScript.

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

Заключение

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

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

Спасибо за внимание!

***

Дополнительные материалы:

Источники

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ