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

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. Одна­ко чти­во реаль­но инте­рес­ное — перед под­готов­кой статьи я спра­шивал кол­лег, и ник­то из них даже и не думал о том, как работал пер­вый про­токол и почему от него отка­зались.

Схема работы OAuth 1.0
Схе­ма работы OAuth 1.0

Здесь у нас сно­ва нем­ного изме­нил­ся ней­минг, обоз­начим все сто­роны:

  1. User — это поль­зователь.
  2. Consumer (пот­ребитель) — при­ложе­ние, которое хочет получить дос­туп к ресур­сам поль­зовате­ля.
  3. 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

Ес­ли ты хоть нем­ного зна­ком с 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"

Продолжение доступно только участникам

Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».

Присоединяйся к сообществу «Xakep.ru»!

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    2 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии