OAuth от и до. Изучаем протокол и разбираем базовые атаки на OAuth

Содержание статьи

  • Что такое OAuth и как он появился
  • Разбираем устройство протокола на реальном примере
  • Authorization Request
  • Consent Screen и Authorization Response
  • Access token request
  • Access token grant
  • API Call и Resource Grant
  • Implicit Grant Flow
  • OAuth и аутентификация
  • Лаба: Authentication bypass via OAuth implicit flow
  • CSRF-атаки на OAuth
  • Лаба: Forced OAuth profile linking
  • Выводы

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

Ду­маю, не нуж­но объ­яснять, что такое аутен­тифика­ция на сай­те. Если ты хочешь искать работу, офор­млять заказы в интерне­те или поль­зовать­ся государс­твен­ными услу­гами, тебя поп­росят под­твер­дить, что имен­но ты вла­делец акка­унта. И даже ког­да это не осо­бен­но нуж­но, раз­работ­чики все рав­но зас­тавят тебя авто­ризо­вать­ся — прос­то что­бы было удоб­нее собирать о тебе дан­ные. Но статья не об этич­ности, поэто­му перей­дем к самой теме.

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

Та­кая тех­нология есть, она дав­но извес­тна и называ­ется OAuth. Имен­но ее исполь­зуют соц­сети и про­чие круп­ные сер­висы, ког­да пред­лага­ют авто­ризо­вать­ся через них.

Стра­ница вхо­да в AliExpress

Этот метод вхо­да стал нас­толь­ко обы­ден­ным, что мно­гие не задумы­вают­ся о том, как он устро­ен, — а зря, ведь дьявол, как извес­тно, кро­ется как раз в деталях. Мелочей здесь нас­толь­ко мно­го, что приш­лось раз­делить гигант­ский матери­ал по этой теме на три час­ти.

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

Нач­нем с базовых атак на OAuth.

 

Что такое OAuth и как он появился

На неофи­циаль­ном сай­те Ааро­на Парец­кого (Aaron Parecki), который собира­ет информа­цию об OAuth, при­веде­но крат­кое, прос­тое, емкое и доволь­но понят­ное опре­деле­ние:

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

Сам про­токол сущес­тву­ет уже дав­но. Идея соз­дания OAuth воз­никла во вре­мя раз­работ­ки Twitter OpenID (не сто­ит путать с OpenID Connect), в нояб­ре 2007 года, ког­да ком­пания соз­давала интегра­цию с Ma.gnolia. Это канув­ший в Лету соци­аль­ный сер­вис зак­ладок, где люди мог­ли делить­ся сох­ранен­ными ссыл­ками на сай­ты.

Сайт Ma.gnolia

Целью интегра­ции Twitter и Ma.gnolia было дать воз­можность Ma.gnolia исполь­зовать вид­жеты информа­цион­ной панели Twitter. Блейн Кук, на то вре­мя ведущий раз­работ­чик в Twitter, заметил, что откры­того механиз­ма, который делеги­ровал бы дос­туп к API, прос­то не сущес­тву­ет.

На тот момент уже были похожие решения, о которых ты, навер­ное, мог и не слы­шать: AuthSub (Google), BBAuth (Yahoo), OpenAuth (AOL), Windows Live ID Web Authentication (Microsoft) и Facebook Auth (Meta). Но они были проп­риетар­ными и потому не годились. Еще более древ­ние методы вро­де переда­чи паролей небезо­пас­ны и неудоб­ны для таких сце­нари­ев. OAuth был пред­ложен как решение этой проб­лемы.

Схе­ма работы OAuth на условном при­мере

Вот как лаконич­но опи­сыва­ют OAuth раз­работ­чики Джон Пан­зер и Эран Хам­мер‑Лахав, которые учас­тво­вали в соз­дании откры­той спе­цифи­кации:

Фи­наль­ный вари­ант реали­зации вер­сии OAuth 1.0 был утвер­жден 4 декаб­ря 2007 года (анонс мож­но най­ти в веб‑архи­ве), а уже в 2008 году этот про­токол под­держал у себя Google, и ауди­тория про­токо­ла начала рас­ти в геомет­ричес­кой прог­рессии. К 2010 году Twitter зас­тавил все сто­рон­ние при­ложе­ния исполь­зовать свою реали­зацию OAuth 1.0.

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

Од­нако это не решило осталь­ные проб­лемы OAuth 1.0 — небезо­пас­ность и неудобс­тво исполь­зования. Раз­работ­чики жалова­лись, что пер­вый OAuth тре­бовал слиш­ком боль­ших крип­тогра­фичес­ких вычис­лений на сто­роне кли­ента — зап­росы нуж­но было под­писывать с помощью HMAC. Мно­гим такая крип­тогра­фия сры­вала сро­ки раз­работ­ки и серь­езно усложня­ла тес­тирова­ние.

За три года с момен­та зарож­дения пер­вой вер­сии про­токо­ла раз­работ­чики при­дума­ли более прос­тое на уров­не реали­зации, но более совер­шенное фун­кци­ональ­но решение, которое прив­носило мно­го новов­ведений и которое ста­ли называть OAuth 2.0. Этот про­токол появил­ся в 2010 году, а его пос­ледняя вер­сия, в качес­тве RFC 6749, была опуб­ликова­на в октябре 2012 года.

 

Разбираем устройство протокола на реальном примере

Что­бы было понят­нее, давай исполь­зовать реаль­ный при­мер. OAuth под­держи­вает нес­коль­ко Flow, или «потоков», которые опре­деля­ют, как имен­но про­исхо­дит обмен информа­цией меж­ду кли­ентом, ресур­сным сер­вером и сер­вером авто­риза­ции (с эти­ми поняти­ями мы поз­накомим­ся нем­ного поз­же), и самый исполь­зуемый в сов­ремен­ном вебе на дес­ктоп­ных сай­тах — это Authorization Code Flow. С него и нач­нем.

Су­щес­тву­ет извес­тный сайт legacy.midjourney.com, который поз­воля­ет соз­давать изоб­ражения с помощью генера­тив­ной ней­росети.

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

В OAuth есть четыре сущ­ности:

  • Resource Owner (вла­делец ресур­са) — под ресур­сом под­разуме­вают­ся раз­личные дан­ные поль­зовате­ля, это может быть поч­та, номер телефо­на, имя, ник­нейм и так далее. Вла­делец ресур­са — тот поль­зователь, который вла­деет эти­ми дан­ными;
  • Application (при­ложе­ние) или Client (кли­ент) — само при­ложе­ние, которое тре­бует дос­туп к ресур­сам поль­зовате­ля. В нашем при­мере это сер­вис Midjourney, который хочет получить наш юзер­нейм, ава­тар­ку и адрес элек­трон­ной поч­ты, на что тре­бует­ся сог­ласие от нас;
  • Authorization Server (авто­риза­цион­ный сер­вер) — сер­вер, который выда­ет OAuth-токены кли­енту пос­ле сог­ласия вла­дель­ца ресур­са. На сай­те Midjourney в качес­тве авто­риза­цион­ного сер­виса выс­тупа­ют Discord и Gmail;
  • Resource Server (сер­вер ресур­сов) — это сайт, где хра­нят­ся поч­та, номер телефо­на, имя поль­зовате­ля и дру­гие дан­ные, которые хочет получить кли­ент. Мы будем вхо­дить через Discord (на котором мы уже зарегис­три­рова­лись ког­да‑то), а зна­чит, Discord и будет выс­тупать в качес­тве это­го сер­вера.

Схе­матич­но Authorization Code Flow в OAuth выг­лядит сле­дующим обра­зом.

Схе­матич­ное изоб­ражение Authorization Code Flow

Ког­да я опи­сывал сер­вер авто­риза­ции и сер­вер ресур­сов, ты мог заметить, что в нашем при­мере это в обо­их слу­чаях Discord. Здесь сто­ит отме­тить, что дей­стви­тель­но в качес­тве этих сер­веров очень час­то выс­тупа­ют одни и те же сер­висы, но с раз­ными эндпо­инта­ми.

Это отлично показы­вает схе­ма из докумен­тации Microsoft.

Аль­тер­натив­ная схе­ма от Microsoft

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

 

Authorization Request

Пер­вый этап называ­ется Authorization Request — зап­рос на авто­риза­цию.

  • Поль­зовать нажима­ет на кноп­ку Sign In на глав­ной стра­нице сай­та, что­бы вой­ти.
  • Сайт показы­вает поп‑ап с выбором соци­аль­ной сети, через которую поль­зователь хочет вой­ти.

    Вход на сайт Midjourney

  • Мы выбира­ем Continue with Discord, при­ложе­ние Midjourney генери­рует ссыл­ку на Discord и редирек­тит нас по ней. Там мы встре­чаем фор­му с прось­бой вой­ти в свой акка­унт.

  • Стра­ница вхо­да в Discord

    При этом URL, по которо­му мы переш­ли, — это не сырая ссыл­ка на вход, вро­де /login. Она осо­бен­на тем, что содер­жит мно­жес­тво парамет­ров, которые были сге­нери­рова­ны при­ложе­нием, и выг­лядит сле­дующим обра­зом:

    <https://discord.com/login>?redirect_to=/oauth2/authorize ?response_type=code &client_id=936929561302675456 &redirect_uri=https://www.midjourney.com/__/auth/handler &state=AMbdmDkycu0e3INVMzD9TaBJsUz4DqLki0MEElniTdiomtU7ejHQwa-zsdFLI3lv11Dlz0syNqa-sQ_fO9vwS_buX5sfKH_JjP1GJfgq8P0yzkAwTKOFRgZgp1Trz61FhuNd99rep6mYA_0NZniAmHeU31AHLer3ENc9UYhlPv3F0d10TtqAo3jrHFTDnzmWBoryBJbuP1dHH7fmo-UKkqedWNxmSNnOqOIE2erMiwibVnP3bhpWZKH-ka0UB6FesAGOGyaNKZG1KY92X8Rai5ceovEDCRId9vW2q_GLwVTixPua1vD1ChLxPi7QgIiRQCk &scope=identify email guilds.join guilds.members.read role_connections.write &context_uri=https://www.midjourney.com

    Раз­берем каж­дый из парамет­ров:

    • client_id — слу­чай­ное зна­чение, которое генери­рует Discord или любой дру­гой сер­вер авто­риза­ции. Этот ID выда­ется сай­ту, в дан­ном слу­чае Midjourney. Для каж­дого из сер­висов‑кли­ентов это зна­чение уни­каль­но. Оно нуж­но для того, что­бы Discord понимал, что за при­ложе­ние зап­рашива­ет дан­ные его поль­зовате­ля, то есть для иден­тифика­ции;
    • redirect_uri — URI, на который Discord дол­жен перенап­равить поль­зовате­ля пос­ле успешной авто­риза­ции. В дан­ном слу­чае он дол­жен вер­нуть его обратно на сайт Midjourney. Нес­коль­ко уяз­вимос­тей завяза­но на неп­равиль­ной обра­бот­ке это­го парамет­ра, их мы рас­смот­рим поз­же;
    • state — уни­каль­ное зна­чение, которое генери­рует­ся на каж­дую сес­сию авто­риза­ции, что­бы защитить­ся от CSRF-атак. В одной из лабора­торий мы тоже научим­ся их экс­плу­ати­ровать для кра­жи чужого акка­унта;
    • response_type — если OAuth — это про­токол авто­риза­ции, то параметр response_type говорит о том, какой флоу это­го про­токо­ла будет исполь­зовать­ся: их нес­коль­ко, и они нем­ного отли­чают­ся друг от дру­га. Сей­час при­ложе­ние под­став­ляет сюда зна­чение code, но тут так­же может быть token или id token;
    • scope — это те дан­ные или эндпо­инты, на которые кли­ент­ское при­ложе­ние Midjourney хочет получить у сер­вера ресур­сов дос­туп.

    В дан­ном слу­чае парамет­ры сле­дующие:

    • identify откры­вает при­ложе­нию воз­можность обра­щать­ся к эндпо­инту /users/@me Discord, что­бы получить информа­цию о поль­зовате­ле, но без email;
    • email — добав­ляет сог­ласие на выдачу email. Пре­дыду­щий эндпо­инт теперь будет воз­вра­щать и его тоже;
    • guilds — нужен, что­бы кли­ент мог обра­щать­ся к эндпо­инту /users/@me/guilds, который воз­вра­щает имя поль­зовате­ля, его ID, бан­нер и дру­гие парамет­ры.

    По­мимо identify, email и guids, есть и дру­гие атри­буты для парамет­ра scope, c ними мож­но озна­комить­ся в до­кумен­тации Discord.

     

    Consent Screen и Authorization Response

    Пос­ле того как мы вош­ли, нас встре­чает экран‑уве­дом­ление, который называ­ется Consent Screen. В нем говорит­ся о том, что кли­ент Midjourney хочет получить дос­туп к дан­ным о нас.

    Стра­ница Consent Screen в Discord

    Источник: xakep.ru

    Ответить

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