Базовое понимание Oauth 2.0

Сегодня, в мире социальных медиа, каждый из нас использует десятки приложений и вебсайтов ежедневно. Oauth 2.0 призван упростить процесс авторизации и, как следствие, сделать жизнь пользователей проще и безопаснее. Возникает вопрос — каким образом?

Oauth 2.0 — что это такое?

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

Eстественно, для этого у Вас должна быть учетная запись у выбранного провайдера.

Термин «провайдер» подразумевает сервис, который владеет данными пользователя и, с разрешения пользователя, предоставляет сторонним сервисам (клиентам) безопасный доступ к этим данным. Приложение, желающее получить данные пользователя — это клиент.

Для примера взята форма логина/регистрации на Aliexpress. В данном случае на форме присутствует выбор из нескольких провайдеров — Google, Facebook, Вконтакте и Twitter.

Вы жмете «войти через Facebook» или «войти через Google», Вас перенаправляют на страницу выбора аккаунта, Вы выбираете свою учетную запись и все — Вы уже залогинились.

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

В отличие от OpenID, OAuth 2.0 может использоваться и для авторизации. То есть, позволяет выдать права на действия, которые сам сервис-клиент сможет производить от лица владельца аккаунта. При этом сам владелец после авторизации может вообще не участвовать в процессе выполнения действий, например, сервис по продаже билетов самостоятельно создает мероприятие в календаре пользователя, или игра размещает на стене в Facebook отчет об очередном завоеванном кубке.

Общая схема OAuth 2.0 :

  1. Клиент запрашивает авторизацию у владельца ресурса.
  2. Клиент получает грант авторизации.
  3. Клиент запрашивает токен доступа путем аутентификации с помощью сервера авторизации и предоставление гранта авторизации.
  4. Сервер авторизации аутентифицирует клиента, проверяя грант авторизации и, если он действителен, выдает токен доступа (access token) и рефреш токен (refresh token).
  5. Клиент запрашивает защищенный ресурс у провайдера и аутентифицируется, представляя токен доступа.
  6. Провайдер проверяет токен доступа и, если он действителен, обслуживает запрос.

Итак, мы видим, что конечная цель — это получить access и refresh токены. Дальше клиент общается с провайдером данных, пока у access токена не кончится срок годности. Затем, чтобы получить доступ к данным провайдера снова, клиенту нужно воспользоваться refresh токеном и отправить запрос на генерацию новой пары access/refresh токенов.

Зачем вообще нужен refresh токен?

Представим ситуацию, когда некто завладел Вашим access токеном и получил доступ к защищенным данным. Именно поэтому у токенов есть срок годности. У access токена он обычно маленький — от нескольких секунд, до нескольких дней, у refresh токена — побольше. Так вот доступ к данным у злоумышленника будет до тех пор, пока токен доступа не протухнет. Допустим, этот некто завладел еще и refresh токеном и воспользовался им раньше чем Вы, тем самым получив новый access токен. В таком случае Вы не можете получить данные с провайдера, но для решения этой проблемы Вам будет достаточно разлогиниться и залогиниться заново — и все! Все старые токены станут недействительными или удаляться (зависит от реализации). После этой процедуры Вы получаете новые access/refresh токены и можете спокойно продолжить работу, а плохой парень, со старыми токенами, остался с носом.

Преимущества и недостатки OAuth 2.0

Из плюсов OAuth 2.0 протокола можно выделить следующее:

    • Обращение к ресурсам происходит по HTTP/HTTPS с указанием токена в заголовках. Это позволяет использовать OAuth практически в любых решения: мобильных и десктоп приложениях, сайтах, и даже в плагинах для браузеров.
    • Возможность авторизации пользователя.
    • Популярность - большинство компаний используют его в своих API.
    • Простота реализации и большое количество “литературы”.
    • Наличие готовых решений, которые можно изменять под свои нужды.

Из минусов:

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

Реализацию OAuth 2.0 подхода на php можно найти на GitHub в нескольких популярных бандлах:

Немного о JWT

JSON Web Token — открытый стандарт для создания токена в json формате. Такой токен состоит из трех частей, разделенных точками: заголовок(header), набор полей (payload) и сигнатура. Первые два блока представлены в json-формате и дополнительно закодированы. Для заголовка есть один обязательный ключ — alg, указывающий алгоритм подписи. Набор полей payload содержит произвольные пары ключ/значения. Также существуют необязательные зарезервированные ключи (ознакомиться).

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

Пример

У нас есть некий ключ SECRET_KEY, его знает только сервер и приложение — клиент (получает его во время установки).

      $SECRET_KEY = "stFalcon";
        $header = '{"typ":"JWT","alg":"HS256"}';
        $payload = '{"sub":"1234567890","name":"alex","admin":true}';
        $unsignedToken = \sprintf("%s.%s", base64_encode($header), base64_encode($payload));
        $signature = hash_hmac('sha256', $unsignedToken, $SECRET_KEY);</p></ol>
     
     
        $tokenEncoded =  \sprintf("%s.%s.%s", base64_encode($header), base64_encode($payload), base64_encode($signature));

    В результате имеем готовый токен -

    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6ImFsZXgiLCJhZG1pbiI6dHJ1ZX0=.MTI5MGZmYTkwMGM2YmE0ODIzNGQ2ZGI4OGYxZTM2NGY5Y2VhYzExN2NiZGNjODA0YmNhN2NhNmM1ZWUzMDQ3NA==

    Теперь проверим токен на валидность -

       $tokenDecodedArr = explode('.', $tokenEncoded);  
     
        $externalHeader = $tokenDecodedArr[0];
        $externalPayload = $tokenDecodedArr[1];
        $externalSignature = $tokenDecodedArr[2];
     
        if ( base64_decode($externalSignature) === hash_hmac('sha256' , \sprintf("%s.%s", $externalHeader, $externalPayload), $SECRET_KEY) ) {
          echo 'matched';
        } else {
          echo 'don’t mathe';
        }

    Таким образом мы проверяем совпадают ли подписи, если да — JWT валидный, т.е. пришел от проверенного источника. Если подписи не совпадают, значит что-то пошло не так — возможно, это является признаком потенциальной атаки.

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

    Заключение

    Подведем итог. OAuth 2.0 это простой протокол авторизации, основанный на HTTP, что дает возможность применять его практически на любой платформе. Он имеет хорошую документацию, и большинство крупных площадок его поддерживают. Так что если вы решили использовать этот протокол в своем проекте — это хороший выбор.