Содержание статьи
- Разница между OAuth 1.0 и OAuth 2.0
- Получение Request Token
- Выдача неавторизованного токена OAuth
- Редирект пользователя на service-провайдера
- Аутентификация пользователя и получение согласия
- Получение access-токена
- Получение доступа к защищенным ресурсам
- Проблемы OAuth
- Знакомство с OpenID Connect
- Как OpenID связан с OAuth
- OAuth не решает задачу аутентификации
- Принцип работы OpenID Connect
- Hybrid Flow
- Что зашито в Identity Token
- OpenID Connect Discovery
- Незащищенная динамическая регистрация клиента
- Лаба: SSRF via OpenID dynamic client registration
- Чек-лист проверок
- Риски
- Проверки
- Автоматизация
- Как защититься
- Сервис-провайдерам
- Клиентским приложениям
- Выводы
info
Это заключительная часть цикла статей о протоколе авторизации OAuth. Читай также статьи «OAuth от и до. Изучаем протокол и разбираем базовые атаки на OAuth» и «OAuth от и до. Ищем цепочки уязвимостей при атаках на авторизацию».
Разница между OAuth 1.0 и OAuth 2.0
Прежде чем мы перейдем к OpenID Connect, давай немного откатимся назад и выясним, в чем же все‑таки разница между OAuth 1.0 и OAuth 2.0 и почему нам приходится разбирать несколько итераций протокола. Для этого привычным образом посмотрим флоу, на этот раз устаревшего OAuth 1.0 — того самого, с которого все и началось в Twitter.
Признаться честно, инфу было найти сложновато, так как первую версию очень быстро вытеснил OAuth 2.0. Однако чтиво реально интересное — перед подготовкой статьи я спрашивал коллег, и никто из них даже и не думал о том, как работал первый протокол и почему от него отказались.
Здесь у нас снова немного изменился нейминг, обозначим все стороны:
- User — это пользователь.
- Consumer (потребитель) — приложение, которое хочет получить доступ к ресурсам пользователя.
- Service Provider (поставщик услуг) — приложение, которое предоставляет доступ к ресурсам пользователя.
Как можно с ходу заметить, сервера авторизации, который есть в OAuth 2.0, здесь нет.
Получение Request Token
Первый запрос после того, как пользователь захотел воспользоваться OAuth, — от потребителя к сервис‑провайдеру. Он нужен на первом этапе, поскольку прежде, чем приложение сможет запросить авторизацию у пользователя, оно должно получить токен запроса — Request Token. Этот токен идентифицирует конкретный запрос авторизации, и его не получится использовать для доступа к ресурсам.
Поскольку Twitter на момент написания статьи все еще поддерживает этот протокол, рассмотрим именно на примере логина в этот сервис. Пример запроса на получение реквест‑токена:
POST /oauth/request_token HTTP/1.1
Host: [api.twitter.com](http://api.twitter.com/)
Authorization: OAuth oauth_callback="https%3A%2F%[2Fwww.example.com](http://2fwww.example.com/)%2Foauth%2Fcallback%2Ftwitter",
oauth_consumer_key="cChZNFj6T5R0TigYB9yd1w",
oauth_nonce="ea9ec8429b68d6b77cd5600adbbb0456",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1318467427",
oauth_version="1.0",
oauth_signature="qCMIWvfCvmP0ZsfWGTPnuaPXsQE%3D"
Все эти параметры (за исключением oauth_callback
) мы видим впервые. Кроме того, они передаются в Authorization-заголовке вместо привычных GET- и POST-параметров. Вот за что они отвечают:
-
oauth_callback
— URL, на который сервис‑провайдер перенаправит пользователя после завершения взаимодействия с ним. Раньше такого параметра не было, он появился в OAuth 1.0a; -
oauth_consumer_key
— идентифицирует приложение для сервис‑провайдера. Назначается при регистрации приложения; -
oauth_nonce
— случайная строка, уникальная для каждого запроса, нужна, чтобы предотвратить replay-атаки; -
oauth_signature_method
— метод, с помощью которого подписываются отправляемые данные; -
oauth_timestamp
— количество секунд, прошедшее с 1 января 1970 года 00:00:00 GMT; -
oauth_version
— версия OAuth, которая будет использоваться во всем процессе; -
oauth_signature
— криптографическая подпись, которая нужна для аутентификации запроса. Автоматически генерируется потребителем на основе его секрета.
Сам механизм подписи довольно прост.
Если ты хоть немного знаком с HMAC, то знаешь, что это криптографически безопасная (то есть необратимая) комбинация определенной строки с общим секретом. Все отправляемые данные конкатенируются, и к ним применяется HMAC с секретом, который известен потребителю и сервис‑провайдеру (oauth_consumer_secret
).
В качестве функции может использоваться HMAC-SHA-1, RSA-SHA-1 или любая другая, которую заранее обговорят потребитель и сервис‑провайдер, спецификация это не регламентирует.
Выдача неавторизованного токена OAuth
После того как Twitter получил запрос, он должен аутентифицировать приложение. Для этого он проверяет, что подпись была создана соответствующим ключом потребителя и его секретом. Если все сошлось, Twitter генерирует токен OAuth вместе с секретом и отдает их в ответе:
HTTP/1.1 200 OK
Content-Type: application/x-www-form-urlencoded
oauth_token=NPcudxy0yU5T3tBzho7iCotZ3cnetKwcTIRlX0iwRl0&
oauth_callback_confirmed=true
Здесь всего два параметра:
-
oauth_token
— неавторизованный токен OAuth. Пока он не авторизован пользователем, он бесполезен. После того как пользователь его авторизует, его можно будет обменять на токен доступа, или access-токен; -
oauth_callback_confirmed
— флаг, установленный в значениеtrue
, чтобы указать, что сервис‑провайдер получил URL, на который нужно перенаправить пользователя. Появился в OAuth 1.0a, нужен, чтобы не допустить атаку session fixation.
Редирект пользователя на service-провайдера
Потребитель не может использовать токен OAuth до тех пор, пока тот не авторизован. Чтобы его авторизовать, он направляет пользователя по ссылке на сервис‑провайдера, где единственный параметр — тот самый токен из предыдущего шага.
HTTP/1.1 302 Found
Location: https://api.twitter.com/oauth/authenticate?oauth_token=NPcudxy0yU5T3tBzho7iCotZ3cnetKwcTIRlX0iwRl0
Браузер пользователя следует редиректу и отправляет примерно такой запрос на страницу Twitter:
GET /oauth/authenticate?oauth_token=NPcudxy0yU5T3tBzho7iCotZ3cnetKwcTIRlX0iwRl0 HTTP/1.1
Host: api.twitter.com
Аутентификация пользователя и получение согласия
Сервис‑провайдер получает этот запрос, проверяет личность пользователя и запрашивает его согласие на предоставление доступа к ресурсам. Спецификация не определяет, как именно он должен аутентифицировать пользователя, но устанавливает ряд обязательных шагов:
- Сервис‑провайдер должен проверить личность пользователя, прежде чем запрашивать согласие. Он может предложить пользователю войти в систему, если тот еще не вошел.
- Сервис‑провайдер предоставляет пользователю информацию о потребителе, который запрашивает доступ. Информация включает в себя продолжительность доступа и ресурсы, к которым потребитель получит доступ.
- Пользователь должен разрешить или отклонить запрос. Если пользователь отказывает потребителю в доступе, сервис‑провайдер не должен разрешать доступ к защищенным ресурсам.
- Когда сервис‑провайдер отображает информацию о потребителе, он должен информировать пользователя, что данные, которые отображаются, указаны самим потребителем и их подлинность невозможно гарантировать (любой может назваться приложением «Пятерочки» или каким угодно). Метод, которым он это делает, в спецификации не определен.
После того как пользователь подтверждает доступ, сервис‑провайдер возвращает его на сайт потребителя, вместе с тем же токеном и параметром oauth_verifier
. Этот параметр появился в OAuth 1.0a и является кодом верификации, который мы уже знаем по OAuth 2.0.
HTTP/1.1 302 Found
Location: [https://www.example.com/oauth/callback/twitter?oauth_token=NPcudxy0yU5T3tBzho7iCotZ3cnetKwcTIRlX0iwRl0&oauth_verifier=uw7NjWHT6OJ1MpJOXsHfNxoAhPKpgI8BlYDhxEjIBY](https://www.example.com/oauth/callback/twitter?oauth_token=NPcudxy0yU5T3tBzho7iCotZ3cnetKwcTIRlX0iwRl0&oauth_verifier=uw7NjWHT6OJ1MpJOXsHfNxoAhPKpgI8BlYDhxEjIBY)
Получение access-токена
Потребитель получает эти параметры и использует уже авторизованный токен, чтобы запросить access_token
, с которым он наконец сможет получить доступ к ресурсам.
Суть этого запроса — обменять авторизованный oauth_token
на access_token
.
В запросе отправляются:
-
oauth_consumer_key
— идентифицирует приложение для сервис‑провайдера. Назначается при регистрации приложения; -
oauth_signature_method
— метод подписи отправляемых данных; -
oauth_signature
— сама подпись, алгоритм генерации которой мы разобрали выше; -
oauth_timestamp
— timestamp, когда была сгенерирована подпись; -
oauth_token
— авторизированный токен, который мы обменяем на access-токен; -
oauth_nonce
— случайная строка, уникальная для каждого запроса, чтобы предотвратить replay-атаки; -
oauth_version
— используемая версия OAuth.
Выглядит запрос примерно следующим образом:
POST /oauth/get_access_token HTTP/1.1
Host: [api.twitter.com](http://api.twitter.com/)
Authorization: OAuth oauth_consumer_key="cChZNFj6T5R0TigYB9yd1w",
oauth_signature_method="HMAC-SHA1",
oauth_signature="nPPh4sLZaCrSAD2moyG6%2Bp8lPuM%3D"
oauth_timestamp="1340653420",
oauth_token="NPcudxy0yU5T3tBzho7iCotZ3cnetKwcTIRlX0iwRl0",
oauth_nonce="OT1DI4X0Wer1ezbuhCnoqCFr9qjrmQZ6",
oauth_version="1.0"
Продолжение доступно только участникам
Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте
Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее
Вариант 2. Открой один материал
Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.
Я уже участник «Xakep.ru»