Перейти к содержимому

Oauth что это такое

  • автор:

Протокол авторизации OAuth 2.0

OAuth 2.0 (RFC 6749) является фреймворком для авторизации, позволяющим получить сторонним приложениям ограниченный доступ к ресурсам HTTP-сервиса.

Стандарт OAuth 2.0 определяет следующие четыре роли:

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

Соответствие сущностей DSS ролям OAuth 2.0 имеет следующий вид:

  • в качестве владельца ресурсов выступает Пользователь КриптоПро DSS;
  • в качестве сервера ресурсов выступают компоненты DSS, содержащие данные Пользователя (например, Сервис Подписи, Сервис Аудита, Хранилище Документов и т.п.)
  • клиентом является приложение, осуществляющее операции в DSS. Приложением может являться браузер, толстый клиент или мобильное приложение.
  • ЦИ DSS выступает в роли сервера авторизации.

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

Протокол OAuth обладает возможностью аутентификации не только Пользователя, но и клиентского приложения, осуществляющего доступ к ресурсам. Для этого протокол предусматривает такие параметры как client_id и client_secret .

сlient_id — это идентификатор клиентского приложения, используемый Центром Идентификации для поиска информации о клиенте.

client_secret является аналогом пароля для клиентского приложения и используется для аутентификации клиентского приложения на ЦИ DSS. Компрометация секрета приводит к компрометации всех клиентских приложений, использовавших client_id , связанный с данными секретом.

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

image

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

Протокол определяет следующие типы разрешения на авторизацию:

  • код авторизации (authorization code);
  • неявный (implicit);
  • учетные данные владельца ресурса (resource owner);
  • учетные данные клиента (не используется КриптоПро DSS).

Работа с ЦИ DSS по протоколу OAuth 2.0 может быть описана одним из представленных ниже сценариев (подробнее). При этом, все сценарии можно разбить на два класса: требующие взаимодействия с пользователем через браузер и не требующие.

Под взаимодействием с пользователем понимается непосредственное взаимодействие Пользователя DSS c Веб-Интерфейсом Центра Идентикации в рамках авторизации клиентского приложения, в то время как сценарии без взаимодействия с Пользователем могут выполняться по схеме Service-Service.

К сценариям, требующим обязательное взаимодействие с пользователям, относятся:

  • Авторизация с использованием кода авторизации
  • Авторизация с использованием типа разрешения Implicit

К сценариям которые могут выполняться без интерактивного взаимодействия с пользователям относят:

  • Авторизация с аутентификацией по сертификату с использованием кода авторизации
  • Авторизация с использованием учетных данных владельца ресурса
  • Получение операторского делегирующего маркера доступа к ресурсу.

OAuth 2.0 простым и понятным языком

Логотип OAuth 2.0

На хабре уже писали про OAuth 1.0, но понятного объяснения того, что такое OAuth 2.0 не было. Ниже я расскажу, в чем отличия и преимущества OAuth 2.0 и, как его лучше использовать на сайтах, в мобильных и desktop-приложениях.

Что такое OAuth 2.0

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

Чем отличаются OpenID и OAuth

Не смотря на то, что объяснений на эту тему уже было много, она по-прежнему вызывает некоторое непонимание.

OpenID предназначен для аутентификации — то есть для того, чтобы понять, что этот конкретный пользователь является тем, кем представляется. Например, с помощью OpenID некий сервис Ололо может понять, что зашедший туда пользователь, это именно Рома Новиков с Mail.Ru. При следующей аутентификации Ололо сможет его опять узнать и понять, что, это тот же Рома, что и в прошлый раз.

OAuth же является протоколом авторизации, то есть позволяет выдать права на действия, которые сам Ололо сможет производить в Mail.Ru от лица Ромы. При этом Рома после авторизации может вообще не участвовать в процессе выполнения действий, например, Ололо сможет самостоятельно заливать фотографии на Ромин аккаунт.

Как работает OAuth 2.0

Как и первая версия, OAuth 2.0 основан на использовании базовых веб-технологий: HTTP-запросах, редиректах и т. п. Поэтому использование OAuth возможно на любой платформе с доступом к интернету и браузеру: на сайтах, в мобильных и desktop-приложениях, плагинах для браузеров…

Ключевое отличие от OAuth 1.0 — простота. В новой версии нет громоздких схем подписи, сокращено количество запросов, необходимых для авторизации.

  1. получение авторизации
  2. обращение к защищенным ресурсам
  • авторизация для приложений, имеющих серверную часть (чаще всего, это сайты и веб-приложения)
  • авторизация для полностью клиентских приложений (мобильные и desktop-приложения)
  • авторизация по логину и паролю
  • восстановление предыдущей авторизации
Авторизация для приложений, имеющих серверную часть

Схема авторизации приложений, имеющих серверную часть

  1. Редирект на страницу авторизации
  2. На странице авторизации у пользователя запрашивается подтверждение выдачи прав
  3. В случае согласия пользователя, браузер редиректится на URL, указанный при открытии страницы авторизации, с добавлением в GET-параметры специального ключа — authorization code
  4. Сервер приложения выполняет POST-запрос с полученным authorization code в качестве параметра. В результате этого запроса возвращается access token

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

Пример

Здесь и далее примеры приводятся для API Mail.Ru, но логика одинаковая для всех сервисов, меняются только адреса страниц авторизации. Обратите внимание, что запросы надо делать по HTTPS.

Редиректим браузер пользователя на страницу авторизации:

> GET /oauth/authorize?response_type=code&client_id=464119& redirect_uri=http%3A%2F%2Fexample.com%2Fcb%2F123 HTTP/1.1 > Host: connect.mail.ru

Здесь и далее, client_id и client_secret — значения, полученные при регистрации приложения на платформе.

После того, как пользователь выдаст права, происходит редирект на указанный redirect_uri:

Обратите внимание, если вы реализуете логин на сайте с помощью OAuth, то рекомендуется в redirect_uri добавлять уникальный для каждого пользователя идентификатор для предотвращения CSRF-атак (в примере это 123). При получении кода надо проверить, что этот идентификатор не изменился и соответствует текущему пользователю.

Используем полученный code для получения access_token, выполняя запрос с сервера:

> POST /oauth/token HTTP/1.1 > Host: connect.mail.ru > Content-Type: application/x-www-form-urlencoded > > grant_type=authorization_code&client_id=464119&client_secret=deadbeef&code=DoRieb0y& redirect_uri=http%3A%2F%2Fexample.com%2Fcb%2F123 < HTTP/1.1 200 OK < Content-Type: application/json

Обратите внимание, что в последнем запросе используется client_secret, который в данном случае хранится на сервере приложения, и подтверждает, что запрос не подделан.

В результате последнего запроса получаем сам ключ доступа (access_token), время его «протухания&raquo (expires_in), тип ключа, определяющий как его надо использовать, (token_type) и refresh_token о котором будет подробнее сказано ниже. Дальше, полученные данные можно использовать для доступа к защищенным ресурсам, например, API Mail.Ru:

> GET /platform/api?oauth_token=SlAV32hkKG&client_id=464119&format=json&method=users.getInfo& sig=. HTTP/1.1 > Host: appsmail.ru
Авторизация полностью клиентских приложений

Схема авторизации полностью клиентских платежей

  1. Открытие встроенного браузера со страницей авторизации
  2. У пользователя запрашивается подтверждение выдачи прав
  3. В случае согласия пользователя, браузер редиректится на страницу-заглушку во фрагменте (после #) URL которой добавляется access token
  4. Приложение перехватывает редирект и получает access token из адреса страницы

Этот вариант требует поднятия в приложении окна браузера, но не требует серверной части и дополнительного вызова сервер-сервер для обмена authorization code на access token.

Пример

Открываем браузер со страницей авторизации:

> GET /oauth/authorize?response_type=token&client_id=464119 HTTP/1.1 > Host: connect.mail.ru

После того, как пользователь выдаст права, происходит редирект на стандартную страницу-заглушку, для Mail.Ru это connect.mail.ru/oauth/success.html:

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

Авторизация по логину и паролю

Авторизация по логину и паролю представляет простой POST-запрос, в результате которого возвращается access token. Такая схема не представляет из себя ничего нового, но вставлена в стандарт для общности и рекомендуется к применению только, когда другие варианты авторизации не доступны.

Пример

> POST /oauth/token HTTP/1.1 > Host: connect.mail.ru > Content-Type: application/x-www-form-urlencoded > > grant_type=password&client_id=31337&client_secret=deadbeef&username=api@corp.mail.ru& password=qwerty < HTTP/1.1 200 OK < Content-Type: application/json

Восстановление предыдущей авторизации

Обычно, access token имеет ограниченный срок годности. Это может быть полезно, например, если он передается по открытым каналам. Чтобы не заставлять пользователя проходить авторизацию после истечения срока действия access token‘а, во всех перечисленных выше вариантах, в дополнение к access token‘у может возвращаться еще refresh token. По нему можно получить access token с помощью HTTP-запроса, аналогично авторизации по логину и паролю.

Пример

> POST /oauth/token HTTP/1.1 > Host: connect.mail.ru > Content-Type: application/x-www-form-urlencoded > > grant_type=refresh_token&client_id=31337&client_secret=deadbeef&refresh_token=8xLOxBtZp8 < HTTP/1.1 200 OK < Content-Type: application/json

Минусы OAuth 2.0

Во всей этой красоте есть и ложка дегтя, куда без нее?

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

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

Заключение

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

Со своей стороны, мы внедрили OAuth 2.0 в API Mail.Ru и, теперь, вы можете использовать возможности протокола для реализации любых клиентов и сервисов, интегрированных с Mail.Ru.

Ссылки

  • Текущая версия драфта стандарта OAuth 2.0
  • Официальный сайт OAuth
  • Рабочая группа по выработке стандарта (архивы)
  • Документация по реализации OAuth 2.0 в Mail.Ru

Что такое OAuth?

img

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

Цель этой статьи – показать вам, как веб-сайт или приложение принимают запросы на вход от пользователей, которые их посещают. У этих платформ есть необходимые полномочия? Есть ли у них право подтверждать вашу личность и получать доступ к некоторым вашим данным от вашего имени? OAuth объясняет весь этот процесс и помогает его упростить. Прочитайте статью до конца, чтобы узнать, как онлайн-проверки стали автоматизированными и как так получилось, что для их завершения требуется всего один клик.

OAuth

Что такое OAuth?

OAuth – это протокол авторизации открытого стандарта, который можно добавить в приложения, чтобы позволить пользователям получать безопасный доступ к их платформе. Например, с помощью этого протокола вы можете указать приложению Facebook разрешить ESPN.com доступ к вашим сообщениям и обновлениям в социальных сетях без обязательного раскрытия ваших учетных данных. Такой доступ позволяет существенно снизить риск. Если на ESPN.com вдруг произойдет утечка данных, то информация, которой вы владеете в Facebook, будет защищена.

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

Примеры OAuth

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

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

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

Хорошим примером здесь может послужить ситуация, когда вас перенаправляют на другой веб-сайт, и вы получаете сообщение с текстом «Эй, вы хотите получить доступ к нашему сайту с учетными данными другого сайта?» Давайте условно назовем веб-сайт, запрашивающий доступ пользователя, получателем, а платформу, на которой вы в данный момент вошли в систему, — отправителем. Когда вы пытаетесь войти на сайт-получатель, вам необходимо будет узнать, заходите ли вы на сайт под тем же именем, что и на сайте-отправителе.

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

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

Как работает OAuth?

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

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

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

OAuth

  • Шаг 1: пользователь показывает свое намерение получить доступ
  • Шаг 2: получатель получает разрешение. Учетные цифровые идентификационные данные будут отправлены вместе с этим разрешением, которые будут использоваться для выявления подделки и проверки источника запроса на права доступа.
  • Шаг 3: пользователь перенаправляется к поставщику услуг или отправителю.
  • Шаг 4: пользователь дает разрешение.
  • Шаг 5: получатель получает маркер доступа.
  • Шаг 6: получатель получает доступ к защищенному ресурсу.

SAML vs OAuth

Многие люди очень легко могут указать на сходства между SAML и OAuth, но их концепции все же очень разные. SAML, также известный как язык разметки утверждений безопасности, представляет собой альтернативный стандарт проверки личности пользователя, который многие организации используют для поддержки функций системы единого входа (SSO). SAML – это функция, позволяющая организациям контролировать тех, кто отвечает за корпоративные ресурсы.

Между SAML и OAuth есть множество различий. SAML использует XML для отправки сообщений, а OAuth – технологию JSON. OAuth разработан для того, чтобы упростить работу с мобильными устройствами, а SAML – для обеспечения повышенного уровня безопасности. Последнее различие является основным. OAuth в основном полагается на API. Именно поэтому многие мобильные приложения, современные веб-сайты, игровые приставки и Интернет вещей используют данный протокол. Как правило, OAuth предлагает пользователям больше возможностей. Чтобы провести аутентификацию пользователя, SAML сбрасывает cookie сессию в браузере пользователя, которая позволяла человеку получать доступ к определенным веб-страницам. Такой вариант отлично подходит для краткосрочного доступа, но не очень подходит для случаев, когда вам необходимо входить в сеть многократно.

OpenID vs OAuth

Если говорить простым языком, то OpenID используется для аутентификации, а OAuth – для авторизации.

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

Оба протокола могут использоваться для выполнения похожих задач, но это вовсе не означает, что они взаимозаменяемы. OpenID обеспечивает подтверждение личности, в то время как OAuth имеет более общее направление использования. Когда клиент использует OAuth, сервер выдает маркер доступа третьей стороне, этот маркер используется для доступа к защищенному ресурсу, а источник проверяет этот маркер. Здесь еще стоит обратить внимание на то, что личность владельца маркера не проверяется.

Сравнение

SAML 2.0

OAuth2

OpenID Connect

Открытый стандарт аутентификации и авторизации

OAuth: описание протокола простым и понятным языком

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

Пример кросс-авторизации

Вернемся в 2005-й год и представим, что мы пишем социальную сеть. В ней имеется форма импорта контактов из адресной книги GMail. Что нужно для доступа к контактам GMail? Конечно, логин и пароль от ящика. Но если мы попросим ввести их на нашем сайте, пользователь заподозрит неладное. Где гарантия, что мы не сохраняем на сервере введенные пароли? Поэтому нам хочется, чтобы пароль вводился только на сайте GMail, и после этого доступ к контактам через API GMail предоставлялся нашей социальной сети (возможно, на время).

Это выглядит следующим образом: форма состоит из единственной кнопки — «Импортировать контакты». После нажатия на нее пользователя временно редиректят на GMail, где он вводит свой логин и пароль (а если уже авторизован, то ничего не вводит). Далее пользователя возвращают обратно на наш сайт, где скрипт уже получает возможность скачать контакты через внутренний API GMail.
  • Consumer: потребитель; скрипт обработки формы импорта контактов в социальной сети.
  • Service Provider: поставщик данных; GMail, содержащий в себе данные адресной книги, интересные для Consumer-а.
  • User: пользователь, имеющий аккаунт как у Consumer-а, так и у Service Provider-а.
  • Protected Resource: личные данные; контакты из адресной книги на GMail (т.е. ресурсы Service Provider-а).
  • Provider API: API GMail, позволяющий любому скрипту получить контакты из адресной книги GMail.
Сейчас я прошу вас закрыть листом бумаги верхнюю часть экрана и в качестве упражнения ответить на вопросы: кто такой Service Provider? что такое Protected Resource? кто такой Consumer и чем он отличается от User-а? где располагается API? Далее в статье мы свободно оперируем этими терминами. Если вы сейчас недостаточно хорошо в них ориентируетесь, могут быть проблемы с пониманием.

Задача OAuth — сделать так, чтобы User имел возможность работать на сервисе Consumer (в соцсети) с защищенными данными Service Provider-а (GMail), вводя пароль к этим данным исключительно на Service Provider-e и оставаясь при этом на сайте Consumer-а. Не так уж и сложно, верно?

Чем OAuth отличается от OpenID?

  1. OpenID — протокол для ускоренной регистрации. OpenID позволяет пользователю без ввода пароля получить аккаунт на каком-либо сервисе, если он уже зарегистрирован где-то еще в интернете. (И потом можно без ввода пароля входить на сервис, будучи авторизованным «где-то».) Например, если у вас есть аккаунт на Яндексе, вы сможете «входить» с его помощью на любой сервис, поддерживающий OpenID-авторизацию.
  2. OAuth — протокол для авторизованного доступа к стороннему API. OAuth позволяет скрипту Consumer-а получить ограниченный API-доступ к данным стороннего Service Provider-а, если User дает добро. Т.е. это средство для доступа к API.

Милицейская аналогия

  • OAuth Consumer: Уголовный розыск.
  • User: сотрудник Уголовного розыска.
  • Service Provider: Картотека архива преступлений.
  1. OpenID: сотрудник Уголовного розыска (User) приходит в Картотеку (Service Provider), предъявляет на входе ксиву (Authorization) и на месте перебирает карточки в поисках информации.
  2. OAuth: сотрудник Уголовного розыска (User) прямо с работы (Consumer) звонит в Картотеку (Service Provider). Он докладывает свою фамилию; если его узнают (Authorization), он просит предоставить список всех преступлений за 1973-й год (API call).

План этой статьи

  1. Рассмотрим проблемы, которые возникают при «ручной» реализации кросс-авторизации.
  2. Поговорим о том, что такое «приложение» и кто такой Consumer.
  3. Коснемся основ криптографии.
  4. Обозначим демо-приложение, которое мы будем писать в этой статье.
  5. Определимся с тестовым сервером OAuth, на котором будем экспериментировать.
  6. Пройдем по всем шагам протокола OAuth и приведем исходники скрипта.

Об изобретении велосипедов

Хороший способ понять что-то — сделать это самому, наступив попутно на все разложенные грабли. Сейчас мы будем изобретать велосипед: попробуем представить, как бы мы решали задачу взаимодействия Consumer-а и Service Provider-а без всяких стандартизированных протоколов.

Во-первых, напишем саму форму импорта контактов с GMail:

Далее попросим разработчиков GMail сделать так, чтобы при переходе пользователя по URI /auth.php ему бы выдавалась форма авторизации (в нашем веломире GMail написан на PHP). После успешного ввода пароля пользователь должен редиректиться на сайт, чей URL указан в параметре retpath. Также дополнительно в URL должен передаваться некоторый секретный ключ, который уже можно использовать для доступа к API GMail.

Итак, после ввода пароля пользователь будет возвращаться к нам на сайт по следующему адресу:

http://oursocialnetwork.ru/import.php?secret=Y49xdN0Zo2B5v0RR

А мы из скрипта /import.php обратимся к API GMail, передадим в него ключ Y49xdN0Zo2B5v0RR и загрузим контакты:

$contacts = $gmailApi->getContacts($_GET['secret']);

Ну что же, давайте теперь считать грабли (потому что шишки считать будет уже поздно).

Грабли первые: подмена адреса возврата retpath

Ну конечно же, вы догадались, что злоумышленник на своем сайте первым делом разместит ссылку

http://gmail.com/auth.php?retpath=http://hackersite.ru/save.php

и заставит вас на нее кликнуть. В результате он получит секретный ключ, который вернул GMail, а значит, и ваши контакты:

http://hackersite.ru/save.php?secret=Y49xdN0Zo2B5v0RR

Грабли вторые: «подслушивание» секретного ключа

Предположим, мы как-то защитили retpath, и он теперь может указывать только на наш сайт. Но проблема с параметром secret остается.

http://oursocialnetwork.ru/import.php?secret=Y49xdN0Zo2B5v0RR

Secret можно подсмотреть из-за спины или перехватить методом прослушивания WiFi-трафика. Или на вашем сайте когда-нибудь найдется XSS-уязвимость, позволяющая «утянуть» секретный ключ. Имея значение secret, злоумышленник сможет прочитать вашу адресную книгу. Значит, нужно обезопасить secret от перехвата (в идеале — вообще его не передавать через URL).

Нужно помнить, что секретный ключ передается не только в URL, но еще и при вызове API-методов. Там тоже возможен перехват. Конечно, использование SSL здесь помогает.

Грабли третьи: слишком много редиректов

Если для каждого вызова API требуется разный secret, то нам придется организовывать столько редиректов на сайт Service Provider-а, сколько у нас вызовов. При интенсивном использовании API это работает очень медленно, да и неудобно порядком…

Грабли четвертые: плохая идентификация Consumer-а

GMail, конечно, хочет знать, кто пользуется его API. Разрешить доступ одним сайтам и запретить — другим… Значит, при формировании запроса в форме импорта контактов Consumer (сайт) должен «представляться» Service Provider-у (GMail-у). В нашем случае эту функцию частично выполняет retpath (имя сайта в нем), но данный способ не универсален, т.к. механизм «представления» должен быть задейстсован еще и при вызове API-методов.

Фундамент OAuth

Примечательно, что «подводных граблей» осталось еще много. Я не буду их здесь описывать, потому что эти грабли лежат в Марианской впадине (глубоко, 10920 м). На описание уязвимостей пришлось бы потратить с десяток страниц. Так что я сразу перейду к описанию OAuth, где все проблемы уже решены.

Есть замечательный цикл статей про OAuth: Beginner’s Guide to OAuth (на английском; от автора с говорящим прозвищем hueniverse). Его изучение отнимет у вас приблизительно 4 часа, если вы до этого момента совершенно не знакомы с темой.

Приложение = Consumer + доступ к API

  • Скрипт формы импорта контактов из GMail (см. пример выше).
  • Приложение для iPhone, позволяющее писать сообщения в Twitter.
  • Прямоугольный виджет на вашем сайте, в котором отображаются последние сообщения чата и есть возможность написать новое.

Token = Key + Secret

Один из принципов OAuth гласит, что никакие секретные ключи не должны передаваться в запросах открытыми (выше в примере мы рассматривали, почему). Поэтому протокол оперирует понятием Token. Токен очень похож на пару логин + пароль: логин — открытая информация, а пароль — известен только передающей и принимающей стороне. В терминах OAuth аналог логина называется Key, а аналог пароля — Secret. Ситуация, когда Secret известен только отправителю и получателю, но более никому, называется Shared Secret.

Итак, если Consumer и Provider каким-то образом договорятся между собой о Shared Secret, они могут открыто обмениваться в URL соответствующими ключами (Key), не опасаясь, что перехват этих ключей будет опасен. Но как защитить URL с Key от подделки?

Сообщение = Документ + Цифровая подпись

«Цифровая подпись» — звучит страшно, но на самом деле это достаточно очевидная вещь. Когда вы ручкой подписываетесь на каком-либо документе, вы удостоверяете, что этот документ написан вами, а не кем-то другим. Ваша подпись как бы «добавляется» к документу и идет с ним в «одном комплекте».

Аналогично, цифровая подпись добавляется к некоторому блоку данных, удостоверяя: тот, кто сформировал эти данные, не выдает себя за другого. Цифровая подпись не шифрует документ, она лишь гарантирует его подлинность! Поставить подпись позволяет тот самый Shared Secret, который известен получателю и отправителю, но более никому.

    Consumer добавляет цифровую подпись к сообщению, в общем виде —

$transfer = $message . "-" . md5($message . $sharedSecret); // $transfer = "Мой телефон 1234567" . "-" . md5("Мой телефон 1234567" . "529AeGWg")
$signatureToMatch = md5($message . $sharedSecret); // $signatureToMatch = md5("Мой телефон 1234567" . "529AeGWg");
Итак, чтобы сформировать MD5-подпись, обязательно знать Shared Secret. (Кстати, кроме MD5 есть и другие алгоритмы необратимого хэширования.) Злоумышленник не знает Shared Secret, поэтому и подпись он подделать не может.

Демонстрация работы OAuth на примере простого приложения

  1. Скрипт, реализующий клиентскую часть протокола. Я написал как раз такой небольшой PHP-скрипт (ссылка на zip-архив). Это виджет, который можно вставлять на PHP-сайты.
  2. Тестовый сервер OAuth, на котором мы сможем экспериментировать. Для этой цели удобно использовать РуТвит: там есть страница http://rutvit.ru/apps/new, которая позволяет добавить тестовое приложение за 30 секунд. (Кстати, URL возврата в форме можно не указывать — мы все равно передаем его из тестового скрипта.)

Вы можете вставить данный виджет на любой PHP-сайт, просто скопировав его код и подправив верстку. Выводятся все твиты с сервиса РуТвит, помеченные указанным хэш-тэгом, а также имеется возможность добавлять новые твиты (тут-то как раз и задействуется OAuth). Виджет использует API и OAuth-авторизацию РуТвита, которые, кстати говоря, совпадают со стандартом API Twitter-а.

В настоящий момент для работы с OAuth в PHP есть только одна сколь-нибудь универсальная и библиотека: OAuth.php by Andy Smith. У нее два недостатка: она написана грязно, и она не обновлялась уже больше года. Ссылки на другие библиотеки приведены на сайте OAuth, однако эти инструменты либо требуют установки PHP extension, либо еще слишком сыры, либо же имеют обширные внешние зависимости от других библиотек (хотя черновик библиотеки для Zend Framework выглядит очень перспективно). Так что, как говорится, «мышки плакали, кололись, но продолжали есть кактус» — будем пользоваться OAuth.php.
  1. Скачайте код скрипта и разверните его в любую удобную директорию на веб-сервере.
  2. Зарегистрируйте новое тестовое приложение на OAuth-сервере.
  3. После регистрации приложения замените параметры OA_CONSUMER_KEY и OA_CONSUMER_SECRET в скрипте на значения, полученные от сервера.
Скрипт специально написан без ООП и максимально «в лоб». Преследовались две цели: а) добиться краткости и понятности кода, б) сделать код идущим параллельно линии повествования в статье (отсюда этот конечный автомат и switch… case). Да, и еще одно. Файл OAuth.php — не самописный, это библиотека от Andy Smith в неизменном виде (наслаждайтесь).

Регистрация приложения и его параметры

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

После регистрации приложения вам выдается 5 параметров, которые требуются для работы с OAuth. Вот как они могут выглядеть:

Здесь Consumer key и Consumer secret — это своеобразные «логин + пароль» вашего приложения (помните выше разговор о токенах? это как раз один из них). Напомню, что Consumer secret — это Shared Secret, известный только отправителю и получателю, но никому больше. Остальные 3 значения задают служебные URL, смысл которых мы сейчас рассмотрим.

OAuth = Fetch Request Token + Redirect to Authorization + Fetch Access Token + Call API

  1. Приложение-Consumer получает Request Token.
  2. Пользователь перенаправляется на сайт Service Provider-а и авторизует там Request Token.
  3. Приложение-Consumer обменивает Request Token на Access Token.
  4. Приложение-Consumer делает авторизованные запросы к API сервиса.

В примере с GMail мы использовали 2 вида удаленных вызовов: а) редирект через браузер; б) обращение к API изнутри скрипта.

И мы вскрыли ряд проблем с безопасностью, что наводит на мысль: вызовов должно быть больше. Так и происходит в OAuth: добавляются еще промежуточные запросы от скрипта Consumer-а к Provider-у, оперирующие токенами. Давайте их рассмотрим.

// Для работы с OAuth нам требуется 3 переменные, сохраняющие свои значения // между загрузками страниц (для простоты - храним их в сессии). session_start(); $S_MSG = &$_SESSION['msg']; $S_REQUEST_TOK = &$_SESSION['REQUEST_TOK']; $S_ACCESS_TOK = &$_SESSION['ACCESS_TOK']; // Путь: // form_is_sent -> // fetch_request_token -> // authorize_request_token (через браузер) -> // fetch_access_token (обмен request_token на access_token) -> // send_msg (через API) // Или: // form_is_sent -> // send_msg (через API) $action = @$_GET['action']; while ($action) < switch ($action) 
  1. Обработка отправки формы. Это не часть OAuth, а часть нашего приложения. Прежде чем обращаться к API Provider-а, мы должны получить от пользователя заказ-наряд на это действие. Вот пример такого «заказа»:
// 1. Запрошена отправка формы. Определяем, с какого шага начинать: // либо с OAuth, либо с отправки сообщения через API. case 'form_is_sent': < // Сохраняем сообщение в сессию, оно нам понадобится позже. $S_MSG = $_POST['msg']; if ($S_ACCESS_TOK && $S_ACCESS_TOK->secret) < // Пользователь уже отправлял комментарии в текущей сессии. $action = 'send_msg'; >else < // Авторизация еще не проведена, запускаем процедуру OAuth. $action = 'fetch_request_token'; >break; >
  • Скрипт Consumer-а обращается к Request token URL Provider-а: например, api.rutvit.ru/oauth/request_token. В запросе передается Consumer key — «логин приложения», а сам запрос подписывается при помощи Consumer secret — «пароля приложения», что защищает его от подделки.
  • В ответ Provider генерирует и возвращает «заполненный мусором» токен, который называется Request Token. Он нам еще пригодится, поэтому мы должны сохранить его где-нибудь — например, в сессионной переменной $S_REQUEST_TOK.
// 2. Запрошено получение Request Token. // Обращаемся к Service Provider через сокет и получаем токен. case 'fetch_request_token': < // Формируем запрос на получение Request Token. $consumer = new OAuthConsumer(OA_CONSUMER_KEY, OA_CONSUMER_SECRET); $req = OAuthRequest::from_consumer_and_token( $consumer, NULL, "GET", "http://api.rutvit.ru/oauth/request_token" ); // Добавляем в запрос цифровую подпись, чтобы не подделали. $req->sign_request(new OAuthSignatureMethod_HMAC_SHA1(), $consumer, NULL); // Получаем Request Token и отправляем его на авторизацию. $parsed = OAuthUtil::parse_parameters(file_get_contents($req->to_url())); $S_REQUEST_TOK = new OAuthToken($parsed['oauth_token'], $parsed['oauth_token_secret']); // Переходим к следующему состоянию. $action = 'authorize_request_token'; break; >
  • Consumer редиректит браузера на специальный Authorize URL Provider-а: например, api.rutvit.ru/oauth/authorize. В параметрах передается Request Token Key.
  • Provider выводит форму авторизации для своего пользователя и, если он авторизовался, редиректит браузер назад. Куда именно? А мы указываем это в параметре oauth_callback.
// 3. Авторизация (подтверждение пользователем) Request Token's через редирект. // Переадресуем браузер на Service Provider для продтверждения доступа пользователем. // При возврате обратно в GET-параметрах будет action=fetch_access_token. case 'authorize_request_token': < // На этот URL вернется браузер после подтверждения. $callbackUrl = "http://" . "?action=fetch_access_token"; // Передаем callback-URL в параметрах (протокол OAuth 1.0; в 1.0a - уже не так!). $authUrl = "http://api.rutvit.ru/oauth/authorize" . "?" . "&oauth_token=key>" . "&oauth_callback=" . urlencode($callbackUrl); // Браузерный редирект. header("Location: $authUrl"); exit(); >
  • Consumer обращается к Access token URL — например, api.rutvit.ru/oauth/access_token, — и просит выдать ему Access Token взамен имеющегося у него Request Token-а. Запрос подписывается цифровой подписью на основе Request Token secret.
  • Provider генерирует и возвращает Access Token, заполненный «мусором». Он также помечает в своих таблицах, что для этого Access Token-а разрешен доступ к API. Наше приложение должно сохранить у себя Access Token, если оно собирается использовать API в дальнейшем.
// 4. Обмен Request Token на Access Token и запись Access Token в сессию. // Сюда вернулись из редиректа после подтверждения доступа пользователем. case 'fetch_access_token': < $consumer = new OAuthConsumer(OA_CONSUMER_KEY, OA_CONSUMER_SECRET); $req = OAuthRequest::from_consumer_and_token( $consumer, $S_REQUEST_TOK, "GET", "http://api.rutvit.ru/oauth/access_token", array() // доп. параметры ); $req->sign_request(new OAuthSignatureMethod_HMAC_SHA1(), $consumer, $S_REQUEST_TOK); // Выполняем запрос и записываем Access Token в сессию. $parsed = OAuthUtil::parse_parameters(file_get_contents($req->to_url())); $S_ACCESS_TOK = new OAuthToken($parsed['oauth_token'], $parsed['oauth_token_secret']); // Переход к отправке сообщения. $action = 'send_msg'; break; >
  • Consumer генерирует запрос к API Provider-а (например, используя POST-запрос согласно REST-идеологии). В запросе передается Access Token Key, а подписывается он при помощи Shared Secret этого токена.
  • Provider обрабатывает API-вызов и возвращает данные приложению.
// 5. Отправляем сообщение. // Оборачиваем URL API в OAuth-контейнер. case 'send_msg': < $consumer = new OAuthConsumer(OA_CONSUMER_KEY, OA_CONSUMER_SECRET); $req = OAuthRequest::from_consumer_and_token( $consumer, $S_ACCESS_TOK, 'POST', 'http://api.rutvit.ru/statuses/update.xml', array('status' =>"#" . TAG . " " . iconv(ENCODING, "UTF-8", $S_MSG)) ); $req->sign_request(new OAuthSignatureMethod_HMAC_SHA1(), $consumer, $S_ACCESS_TOK); // Отправляем POST-запрос. $h = curl_init(); curl_setopt($h, CURLOPT_URL, $req->get_normalized_http_url()); curl_setopt($h, CURLOPT_POST, true); curl_setopt($h, CURLOPT_RETURNTRANSFER, true); curl_setopt($h, CURLOPT_POSTFIELDS, $req->to_postdata()); $resp = curl_exec($h); $code = curl_getinfo($h, CURLINFO_HTTP_CODE); // При успехе - редирект обратно на страницу с виджетом. if ($code != 200) < e($resp); exit(); >header("Location: "); exit(); >

Конец скрипта: вывод виджета

Окончание скрипта должно быть понятно и без подробных разъяснений.

// конец case > > // Получаем все имеющиеся твиты. $text = file_get_contents("http://api.rutvit.ru/search.xml?rpp=5&q=" . urlencode("#" . TAG)); $TWEETS = new SimpleXMLElement($text); // Shortcut для вывода сообщения с перекодировкой и квотингом. function e($text, $quote = 1) < $text = iconv("utf-8", ENCODING, $text); echo $quote? htmlspecialchars($text) : $text; >?> .hiddenLink 
status as $tweet)
user->screen_name)?>: text_formatted, 0)?>
?>

Полезные ссылки по OAuth

  • Оригинал текущей статьи на dklab.ru
  • Официальный сайт OAuth.
  • OAuth.php by Andy Smith.
  • Реализация протокола OAuth на всевозможных языках программирования.
  • Beginner's Guide to OAuth: статья про OAuth на английском, очень рекомендую к прочтению.
  • http://rutvit.ru/apps/new: регистрация приложения на OAuth-сервере РуТвита.
  • Полный исходный код примеров этой статьи.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *