Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Протокол OpenID Connect — это наследник OAuth. Поскольку у OAuth есть множество проблем, в том числе с безопасностью, ему на смену приходит более совершенный вариант. Но и он при неправильном обращении может оставлять лазейку для злоумышленников. В этой статье мы разберем такие проблемы в OpenID Connect и покажем их на примере лабы PortSwigger. info
Это заключительная часть цикла статей о протоколе авторизации OAuth. Читай также статьи «OAuth от и до. Изучаем протокол и разбираем базовые атаки на OAuth» и «OAuth от и до. Ищем цепочки уязвимостей при атаках на авторизацию».
Прежде чем мы перейдем к OpenID Connect, давай немного откатимся назад и выясним, в чем же все‑таки разница между OAuth 1.0 и OAuth 2.0 и почему нам приходится разбирать несколько итераций протокола. Для этого привычным образом посмотрим флоу, на этот раз устаревшего OAuth 1.0 — того самого, с которого все и началось в Twitter.
Признаться честно, инфу было найти сложновато, так как первую версию очень быстро вытеснил OAuth 2.0. Однако чтиво реально интересное — перед подготовкой статьи я спрашивал коллег, и никто из них даже и не думал о том, как работал первый протокол и почему от него отказались.
Схема работы OAuth 1.0
Здесь у нас снова немного изменился нейминг, обозначим все стороны:
Как можно с ходу заметить, сервера авторизации, который есть в OAuth 2.0, здесь нет.
Первый запрос после того, как пользователь захотел воспользоваться 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, то знаешь, что это криптографически безопасная (то есть необратимая) комбинация определенной строки с общим секретом. Все отправляемые данные конкатенируются, и к ним применяется HMAC с секретом, который известен потребителю и сервис‑провайдеру (oauth_consumer_secret
).
В качестве функции может использоваться HMAC-SHA-1, RSA-SHA-1 или любая другая, которую заранее обговорят потребитель и сервис‑провайдер, спецификация это не регламентирует.
После того как 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.
Потребитель не может использовать токен 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_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"
Источник: xakep.ru