Аутентификация в веб-приложениях

Аутентификация в веб-приложениях #

Васильев Андрей Михайлович, 2022

Версии презентации


Вопросы доступа к данным #

Защита #

Доступ к данным должен осуществляться только уполномоченными лицами

Разделение на читателей и администрацию #

  • Большинство пользователей может только просматривать информацию
  • Администрация может добавлять новые элементы на ресурс

Системы разделения полномочий #

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

Идентификация, аутентификация и авторизация #

  • Идентификация — процедура, в результате выполнения которой для субъекта идентификации выявляется его идентификатор, однозначно определяющий этого субъекта в информационной системе
  • Аутентификация — это процедура проверки подлинности субъекта, например путём сравнения введённого им пароля с паролём, сохранённым в базе данных
  • Авторизация — предоставление субъекту прав на выполнение определённых действий, разрешение на выполнение действия

Пример процедуры аутентификации #

  1. Пользователь заходит на сайт и нажимает на кнопку «войти в систему»
  2. Система показывает экран для входа в систему
  3. Пользователь вводит имя пользователя, идентифицирует себя
  4. Пользователь вводит пароль,
  5. Пользователь нажимает на кнопку «Войти», начинает процедуру аутентификации
  6. Система получает введённые имя пользователя и пароль, завершая аутентификацию
  7. Аутентификационный токен передаётся пользователю в ответе
  8. Браузер выполняет запрос к серверу, сервер использует аутентификационный токен для авторизации последующих действий пользователя

Почему так сложно? #

  • Аутентификация без идентификации невозможна — нельзя определить субъекта, операцию выполнить невозможно
  • Авторизация без аутентификации невозможна — нельзя понять какие действия можно разрешать данному пользователю
  • Авторизация без идентификации возможна — публичная информация может быть доступна любым пользователем. Но даже в этом случае авторизация выполняется, если явно не обрабатывается приложением

Как оно может стать ещё сложнее:

  • Вариантов решения задач очень много
  • Зачастую требуется реализовать множество вариантов аутентификации в рамках одного приложения
  • Простые процедуры выполнения аутентификации могут быть не безопасны, в приложениях следует реализовывать сценарии, проверенные специалистами по безопасности

Варианты аутентификации пользователей #

  • Аутентификация согласно встроенным возможностям протокола HTTP
  • Аутентификация с сохранением сессии
  • Аутентификация с использованием сертификатов
  • Аутентификация по одноразовому паролю
  • Аутентификация по ключам доступа
  • Аутентификация по токенам
  • Стандарты аутентификации OAuth и OpenID Connect

Аутентификация по протоколу HTTP #

Задача аутентификации возникла давно и в рамках стандарта HTTP утверждено несколько способов аутентификации: IANA

sequenceDiagram participant cli as Клиент participant serv as Сервер cli ->> serv : GET-запрос по пути PATH serv ->> cli : Ответ 401, Unauthorized, заголовок WWW-Authenticate cli ->> cli : Формирует ответ cli ->> serv : GET-запрос по пути PATH с заголовком Authorization alt Данные введены верно serv ->> cli : Ответ 200 с указанным документом else serv ->> cli : Ответ 403, Forbidden end

  • Для указания поддерживаемого способа аутентификации сервер передаёт HTTP-заголовок WWW-Authenticate
  • Данные на сервер передаются в заголовке Authorization
  • После успешной авторизации пользователя браузер сохраняет данные в заголовке Authorization и передаёт их при каждом запросе серверу

Базовая HTTP-аутентификация, RFC7617 #

sequenceDiagram actor user as Пользователь participant brow as Браузер participant serv as Сервер user ->> brow : Открывает ссылку в интерфейса brow ->> serv : Посылает GET-запрос на ссылку serv ->> brow : Ответ с кодом 401, Unauthorized brow ->> user : Окно для ввода имени имени и пароля user ->> brow : Вводит имя пользователя и пароль brow ->> serv : Передаёт данные в заголовке Authorization serv ->> serv : Выполняет проверку введённых данных serv ->> brow : Возвращает результат запроса

Особенности базовой аутентификации #

  • Браузер сохраняет введённые данные и добавляет заголовок ко всем последующим запросам серверу
  • Для сброса введённых данных необходимо перезапустить браузер
  • Данные базовой аутентификации передаются в открытом виде и может быть перехвачена. Необходимо использовать зашифрованное SSL-соединение
  • Данные базовой аутентификации можно передать в рамках URL-запроса
    https://username:password@example.com/

Имя пользователя и пароль передаются в формате имя:пароль и отделяются от пути символом @


Аутентификация с сохранением сессии #

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

Используются в веб-приложениями для:

  • Управления сеансами пользователя, аутентификации, корзины
  • Персонализации контента
  • Мониторинга поведения пользователя
sequenceDiagram participant cli as Браузер participant ser as Сервер cli -> ser : Запрос данных ser -> cli : Ответ с заголовком(ами) `Set-Cookie` cli -> ser : Запрос с заголовком `Cookie`

Заголовки Set-Cookie и Cookie #

Заголовки Set-Cookie устанавливаются сервером в рамках своего ответа

Простой заголовок может выглядит так:

Set-Cookie: <имя cookie>=<значение cookie>

Таких заголовков в ответе сервера может быть несколько:

Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry

Браузер будет передавать их клиенту в рамках заголовка Cookie:

Cookie: yummy_cookie=choco; tasty_cookie=strawberry

От клиента на сервер может передаваться несколько куков


Время жизни куков #

  • Сессионные cookie удаляются при закрытии клиента, то есть существуют только на протяжении текущего сеанса. Однако сеанс автоматически не завершается, что делает их вечными
  • Постоянные cookie удаляются не с закрытием клиента, а при наступлении определённого интервала времени
Set-Cookie: id=5aoeu; Expires=Wed, 20 Nov 2010 10:15:00 GMT;

Безопасность HTTP куков #

  • Данные передаются в открытом виде, для защиты нужно использовать SSL-шифрование
  • Для защиты данных куки от доступа из JavaScript, необходимо использовать атрибут HttpOnly
  • Можно явно указать домены, с которых будет доступна информация с помощью атрибутов Domain и Path
  • «Раздражающее» сообщение о куках необходимо по законодательству сообщать пользователю об их использовании веб-приложением и их назначением. Многие JavaScript-библиотеки добавляют свои куки

Аутентификация с сохранением сессии #

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

Ключевая задача — сформировать токен аутентификации и сохранить его в куки

sequenceDiagram participant cli as Браузер participant ser as Сервер cli ->> ser : GET-запрос на аутентификацию ser ->> cli : 200, HTML-документ с формой cli ->> cli : Пользователь заполняет форму и нажимает кнопку «отправить» cli ->> ser : POST-запрос с данными формы, именем пользователя и паролём ser ->> cli : 302, с заголовком `Set-Cookie`, содержащим токен аутентификации cli ->> ser : GET-запрос с заголовком `Cookie` и токеном аутентификации

Аутентификация с использованием сертификатов #

  • Сертификат представляет собой набор атрибутов, идентифицирующих владельца и подписанный центром сертификации
  • Центр сертификации выступает в роли посредника, который гарантирует подлинность
  • Сертификат криптографически связан с закрытым ключом и позволяет подтвердить факт владения сертификатом
flowchart TB app[Веб-приложение] ca[Центр сертификации] cli[Клиент] app -- Доверяет центру --> ca ca -- Выдаёт сертификат --> cli cli -- Передаёт сертификат приложению при запросе --> app

Проверка сертификата сервером #

  1. Сертификат должен быть подписан доверенным центом сертификации
  2. Сертификат должен быть действительным на данную дату (они выдаются на срок от нескольких месяцев до нескольких лет)
  3. Сертификат не должен быть отозван соответствующим центром сертификации

Приложение может использовать содержимое сертификата для выполнения авторизации

  • Имя владельца
  • Название эмитента сертификата
  • Серийный номер сертификата
  • Отпечаток открытого ключа

Ключевая проблема: сертификат надо создать, передать пользователю и, главное, не передать другим пользователям


Аутентификация по одноразовым паролям #

Обычно применяется для реализации двухфакторной аутентификации:

  • Пользователю необходимо пройти классическую схему аутентификации
  • Затем необходимо передать одноразовый пароль

Источниками одноразовых паролей могут быть:

  • Аппаратные или программные токены (Яндекс Ключ, Google Authenticator)
  • Случайные коды, передаваемые по SMS или другой канал связи
  • Распечатка со списком заранее сформированных паролей

В веб-приложениях обычно используется:

  • После прохождения аутентификации с помощью формы
  • Для подтверждения важных действий внутри приложения

Аутентификация по ключам доступа #

Данный способ часто применяется для аутентификации устройств, сервисов или других приложений при обращении к веб-сервисам

  • Секретные данные — длинные уникальные строки, замещающие имя и пароль
  • При создании ключа можно ограничить время его действия
  • Ключ нельзя передавать третьим лицам или по небезопасным каналам

Ключи можно передавать в параметрах запроса, в теле запроса, в заголовках запроса

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


Аутентификация по токенам #

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

  • Веб-приложение, обеспечивающее аутентификацию, называется identity provider или authentication service (в случае, если происходит ещё и авторизация)
  • Другие приложения в рамках данной схемы называются service provider
sequenceDiagram participant cli as Клиент participant iden as Провайдер идентификации participant ser as Поставщик услуг cli ->> iden : Запрос на получение токена для поставщика услуг iden ->> cli : Формирует и возвращает токен cli ->> ser : Запрос к услуге, включающий токен ser ->> cli : Проверяет токен и возвращает ответ на запрос

Аутентификация браузера в провайдере #

Предыдущий процесс можно реализовать в специализированных клиентах, однако при использовании браузера процедура становится более сложной

sequenceDiagram participant brow as Веб-браузер participant iden as Провайдер идентификации participant ser as Поставщик услуг brow ->> ser : Посылает GET-запрос по адресу ser ->> brow : Ответ с перенаправлением на службу идентификации brow ->> iden : GET-запрос по указанному адресу iden ->> brow : Страница для ввода аутентификационных данных brow ->> iden : Передача данных с формы iden ->> brow : Отправка HTML-формы с введённым токеном brow ->> ser : Автоматическая отправка формы после открытия ser ->> brow : Показ запрошенной страницы

Варианты аутентификации по токену #

Существует множество стандартов, среди наиболее популярных: OAuth, OAuth 2.0, OpenID Connect, SAML, WS-Federation

Внутри токена содержится дополнительная информация:

  • кто сгенерировал токен
  • кто может быть получателем токена
  • срок действия
  • набор сведений об аутентифицированной сущности

При получении токена его необходимо проверить на соответствие требованиям приложения


Форматы токенов #

Simple Web Token #

Набор пар имя-значение в формате кодирования HTML form, описывает стандартные ключи Issuer, Audience, ExpiresOn и HMACSHA256. Токен подписывается симметричным ключом

JSON Web Token, JWT #

Содержит три блока, разделённых точками: заголовок, набор полей и подпись. Первые два блока закодированы в JSON-формате и закодированы в base64. Подпись может быть сформирована как симметричными, так и ассиметричными алгоритмами шифрования

Security Assertion Markup Language (SAML) #

Определяет токены в XML-формате, включающем информацию об эмитенте, субъекте, необходимые условия для проверки токена. Подпись осуществляется при помощи ассиметричной криптографии. Содержат механизм для подтверждения владения токеном


Стандарты OAuth и OpenID Connect #

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

Приложению для своей работы могут потребоваться данные из другой системы:

  • Список контактов данного пользователя
  • Список файлов данного пользователя
  • Почтовый адрес данного пользователя

В рамках стандарта OpenID Connect на основе OAuth разработан слой учётных данных, в рамках которого сервер авторизации предоставляет идентификационный токен

Большие технологические компании и государства предоставляет возможности по аутентификации с помощью данных протоколов: Госуслуги, VK, Яндекс, Сбербанк


Реализация аутентификации по паролю #

Для упрощения данной задачи в промышленных приложениях лучше всего делегировать задачи идентификации и аутентификации внешним приложениям с использованием протоколов OpenID Connect и OAuth 2.0

Для решения задачи аутентификации своими силами необходимо:

  • Корректно сохранять данные для идентификации и аутентификации
  • Сохранять средства быстрой проверки аутентификации, токены

Хранение аутентификационных данных #

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

  • Имя пользователя
  • Зашифрованный пароль пользователя

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

Для защиты пароля рекомендуется использовать схему с добавлением соли

flowchart LR salt("Соль") pass("Пароль") com["Объединение"] full("Соль + пароль") hashing["Хеш-функция"] hashed("Хеш пароля") salt --> com pass --> com com --> full full --> hashing hashing --> hashed

Базы данных обычно предоставляют возможности по выполнению хеширования


Особенности использования соли #

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

Хранение и проверка сессионных токенов #

Для верификации сессионных токенов необходимо:

  • доверять данным, пришедшим от пользователя, т.е. отказаться от проверки данных
  • хранить сессионный токен на стороне сервера для сверки
  • применять схемы с шифрованием данных или подписью данных в токене

Хранение сессионных токенов на стороне сервера несёт ряд сложностей:

  • сколько токенов может быть выдано конкретному пользователю?
  • сколько пространства потребуется для хранения всех выданных токенов?
  • сколько времени уйдёт на выявление их корректности?

Последняя схема имеет ряд проблем:

  • надо корректно реализовать криптографические схемы
  • сложно отозвать скомпрометированные токены

© A. M. Васильев, 2022, CC BY-SA 4.0, andrey@crafted.su