eFusion 30 июля 2020

↩️ «Выйди и снова зайди, только правильно». Всё ли вы знаете об OAuth 2.0?

Благодаря открытому протоколу OAuth, необязательно заводить для каждой сайта отдельные логин и пароль – можно авторизоваться через Google, Facebook или другой ресурс. Рассказываем, как устроен под капотом протокол OAuth 2.0.
0
489

Социальные сети, потоковая передача контента, воркспейсы – везде мы заходим через учетные записи, которые могут содержать личную информацию. Изолированные приложения становятся взаимосвязанными: Twitter позволяет новостным сайтам твитить напрямую, Discord ищет предполагаемых друзей на Facebook, а Jira создает учетки с помощью профилей Github.

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

Терминология OAuth

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

  • Владелец ресурса (Resource Owner) – объект, предоставляющий доступ к защищенным ресурсам.
  • Ресурсный сервер (Resource Server) – сервер, на котором размещаются защищенные ресурсы и обрабатываются запросы на доступ.
  • Клиент (Client) – приложение, которое хочет получить доступ к ресурсному серверу и выполнять действия от имени владельца ресурса. Конфиденциальным клиентам (серверные приложения) можно доверять надежное хранение токена, необходимого для доступа к ресурсам, а публичным (мобильные и JS-приложения) – нельзя.
  • Сервер авторизации (Authorization Server) – сервер, который знает владельца ресурса и может авторизовать клиента для доступа к ресурсному серверу.

Функционирование протокола OAuth

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

В том же ключе OAuth используется в социальных сетях. Например, при авторизации в Spotify через Facebook приложение Spotify получает доступ лишь к ограниченному набору данных.

Рис. 1. Используя OAuth, клиент (Spotify) может получить доступ к ресурсному серверу (Facebook) без учетных данных от имени владельца ресурса (Боба).
Рис. 1. Используя OAuth, клиент (Spotify) может получить доступ к ресурсному серверу (Facebook) без учетных данных от имени владельца ресурса (Боба).

При выводе всплывающего окна OAuth работает в фоновом режиме (Рис. 2):

  • Spotify отправляет Бобу сообщение с запросом доступа к его публичному профилю, друзьям, почте и т. д.
  • Боб разрешает Spotify сбор указанных данных.
  • Spotify отправляет ответ в API Facebook.
  • Facebook API проверяет присланный ответ и возвращает Spotify токен для доступа к защищенным ресурсам.
  • Spotify высылает токен на другой API Facebook, предоставленный сервером авторизации.
  • Facebook API отправляет запрошенные данные в Spotify.
Рис. 2. Делегирование доступа к данным Facebook для Spotify
Рис. 2. Делегирование доступа к данным Facebook для Spotify

Заглянем под капот OAuth

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

Области и токены OAuth

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

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

Условно можно выделить четыре типа областей:

  • доступ для чтения;
  • доступ на запись;
  • доступ для чтения и записи;
  • без доступа.

Определение области действия – мощный инструмент для определения того, какой уровень допуска к пользовательским данным разрешен третьим лицам. Чтобы понять, как это можно использовать, прочитайте документацию Slack и Google, которые демонстрируют различные вариации параметров настройки.

Существует еще один тип токенов – обновляемый (refresh tokens), который используется для автоматического получения нового экземпляра, когда старый больше не функционируют (expired). Такие приложения, как Facebook, могут обеспечить ещё бóльшую степень защиты, периодически проверяя авторизацию с помощью принудительного использования дополнительных refresh-токенов для получения access-токенов. Refresh tokens имеют важную особенность: они могут быть отозваны путем их аннулирования и возврата клиентского доступа к привилегированным ресурсам.

Рис. 3. OAuth поток
Рис. 3. OAuth поток

Разрешения и потоки OAuth

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

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

Покупка онлайн:

  • перейти на сайт театра;
  • найти сеанс;
  • добавить билет в заказ;
  • оплатить;
  • получить билет на e-mail.

Разрешения (grants) диктуют клиенту порядок операций по получению access-токена. Этот уникальный порядок называется потоком.

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

  • Код разрешения авторизации (Authorization Code Grant) – наиболее распространенный тип разрешений (Рис. 4). Клиент получает уникальный код, выданный сервером авторизации, который затем обменивается на токен.
  • Код разрешения авторизации с PKCE – этот вариант используется для публичных клиентов, которым нельзя доверять хранение учетных данных. Используя расширение PKCE (Public Key for Code Exchange), клиент и сервер обмениваются хэшем, чтобы убедиться, что связь не скомпрометирована.
  • Учетные данные клиента – иногда клиенты запрашивают доступ для себя, а не для владельца ресурса. Эти экземпляры используют внутренние службы, которым требуется доступ к облачному хранилищу. В этом случае клиент сделает запрос, включающий client_id и client_secret, которые сервер авторизации проверяет для выдачи access-токенов. Этот тип разрешений должен использоваться только с конфиденциальными клиентами.
  • Код устройства – используется для устройств, подключенных к интернету, которые не имеют браузеров или снабжены неудобными виртуальными клавиатурами, например, игровая консоль или Smart TV.

Пример: GitHub SSO

Изучим описанные концепции на примере. Teleport – опенсорсный инструмент удаленного доступа, позволяющий юзерам входить в систему через Github single sign-on (SSO) с использованием OAuth. Действующие лица:

  • Client: Teleport.
  • Resource Owner: пользователь Teleport.
  • Authorization Server: сервер авторизации Github (GAS).
  • Resource Server: ресурсный сервер Github (GRS).
Рис. 4. Поток разрешения авторизации
Рис. 4. Поток разрешения авторизации

Рассмотрим поток шаг за шагом.

Шаг 1. Пользователь Teleport получает доступ к приложению Teleport.

Шаг 2. Приложение предлагает пользователю Teleport войти с помощью Github SSO.

Шаг 3. Пользователь Teleport нажимает «Войти» и перенаправляется на другую страницу со своими параметрами, передаваемыми в HTTPS GET запросе:

  • authorization_server – URL-адрес, обработанный GAS. Для GitHub это https://github.com/login/oauth/authorize
  • response_type=code – оповещает GAS, что Teleport ожидает код авторизации
  • client_id – передает GAS строку, которую он может проверить по реестру авторизованных клиентов. В коде ниже это 12345.
  • redirect_uri – сообщает GAS, на какой URL направить юзера со всеми переменными. Здесь используется следующий: https://teleport.example.com:3080/v1/webapi/github/callback
  • scope – определяет ограничения доступа к ресурсам
  • state – случайно генерируемая Teleport строка для идентификации клиента и сервера авторизации (в примере используется Syl)

Собрав воедино все, получим следующую строку приглашения:

https://github.com/login/oauth/authorize?response_type=code&client_id=12345&redirect_uri=https://teleport.example.com:3080/v1/webapi/github/callback&scope=read:org&state=syl

Шаг 4. Как только GAS получит запрос, он проверит client_id в реестре. Зная, что Teleport ожидает код авторизации, GAS отправит пользователя обратно на URL-адрес с переданными параметрами:

        https://teleport.example.com:3080/v1/webapi/github/callback?code=pkzdZumQi1&state=syl
    

Шаг 5. После получения кода Teleport автоматически попросит GAS обменять код на токен с параметрами code, redirect_uri и client_id. Для обмена используется POST-запрос:

        POST https://github.com/login/oauth/access_token grant_type=authorization_code& code=pkzdZumQi1& redirect_uri=https://teleport.example.com:3080/v1/webapi/github/callback& client_id=12345& client_secret=gravitational
    

Шаг 6. Используя client_secret и code, сервер авторизации может проверить запрос клиента Teleport и выдать токен, в который зашивается область и время жизни:

        { “access_token”:“IEZKr6ePPtxZBEd”, “token_type”:”bearer” “scope”:“read:org”, “expires_in”:3600 }
    

Шаг 7. Теперь, когда маркер получен, делаем запрос к API от имени пользователя Teleport и получаем желаемое:

        GET /users/org Host: api.github.com Authorization: Bearer IEZKr6ePPtxZBEd …
    

Шаг 8. Наконец, GitHub API пропускает юзера.

Заключение

Несмотря на часто упускаемое из виду удобство, OAuth-это сложный протокол, реализация которого потребует времени. Пример, который мы рассмотрели выше – один из сотен вариантов того, как может выглядеть поток OAuth.

***

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

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

Источники

РУБРИКИ В СТАТЬЕ

МЕРОПРИЯТИЯ

Хотите ещё что-нибудь узнать о протоколе OAuth?

ВАКАНСИИ

Senior JS разработчик
по итогам собеседования

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

BUG