OpenID Connect 1.0 поясення от А до Я

У OpenID Connect є специфікація є туторіали, статті . Досить безглуздо ліпити чергову покрокову інструкцію, провідну від глибокого здивування до працюючої наскрізний авторизації і аутентифікації. Завдання тексту нижче інше, описати лежачі в основі специфікацій ідеї (їх більше однієї).

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

 

  1. Завдання мінімум — просто не пускати кого попало до якогось свого ресурсу. Закриваємо його логіномпаролем, хто знає підходящу пару з логіна і пароля на ресурс потрапить, хто ні — ні. Ця штука називається аутентифікація, для неї можна використовувати не тільки логіни з паролями (код з СМС, наприклад, або апаратний USB-ключ), але це несуттєві деталі для нашої теми. Так само опущу обов’язковий абзац про небезпеку передачі паролів через інтернет у відкритому вигляді, за яку ми всі не любимо access Basic authentication.

Краще зауважу ось що: ніхто з користувачів не любить вводити логіни з паролями. Коди СМС нітрохи не краще, а USB-ключі так і зовсім просто ненавидять. Щоб не змушувати користувача вводити логін з паролем на кожен запит сервер у відповідь на них надсилає сходинку абракадабри, іменовану сесійним ключем. І далі цей ключ чіпляється клієнтом до кожного запиту на сервер (зазвичай HTTP-заголовком, але це не суттєво), і сервер перевіряє, чи є у нього така сесія.

Сесія з ключиком — явище, за визначенням, тимчасовий, золотий перетин для часу життя сесії становить, приблизно, “поки відкрита вкладка браузера, але не довше доби”

2. Пустили кого треба — це добре. Тепер потрібно зрозуміти, кого саме ми пустили. І не тільки вивести те, що він ввів в якості імені в правому верхньому кутку, але і вирішити, до чого його підпускати, а чого немає.

І все це називається — авторизація. І не впевнений щодо вас, але я плутаю її з аутентифікацією постійно. Щоб не плутати — це мнемонічне правило, “авторизація” — від слова “автор”, “автора” пишуть на обкладинках книг, і там ніколи не пишуть “валідований член спілки письменників”. Автор — це завжди абсолютно конкретна людина. А значить авторизація це процес, коли ми розуміємо кого конкретно ми запустили по логіну і паролю.

3. Ок. У нас є сайт, на сайті щось секретне, на вході в секретну частину ми вимагаємо пароль, кожному показуємо тільки його секретики, і не показуємо чужі. Життя не стоїть на місці, і у нас з’явився ще один сайт. І тут ми знову зустрічаємося з проблемою пункту 1, ніхто не любить вводити логіни і паролі! Можна об’єднати базу користувачів і це позбавить їх від необхідності реєструватися двічі, але як позбавити їх від повторного введення логіна і пароля на вході? З урахуванням існування такої штуки як Same Origin Policy (а наші сайти розташовані, природно, на різних доменах, значить куки з ключиком сесії одного іншому не видно)? Тут, для додання важливості моменту, я почну новий пункт.

Читайте також  Reddit зламаний, витекла база з паролями та email за 2005-2007 роки

4.

SSO, Single Sign On — якою б не була реалізація, майкрософтовський Kerberos, SAML або щось OAuth 2.0, поверх якого побудований OpenID Connect, про який я вам тут пишу, насправді під капотом завжди одне і те ж: є окремий сервер авторизації, і будь-який бажаючий прийняти користувача перенаправляє користувача на нього. Якщо ви вже авторизований, сесія підхоплюється, і він тут же летить з сервера авторизації назад і потрапляє куди хотів. Якщо не авторизований — сервер авторизації вирішує цю проблему як вміє, запитом логіна з паролем як правило, і вже при успішному вирішенні відправляє користувача назад.

При цьому SAML на даний момент рішення, так скажемо, застаріле. А Kerberos взагалі абсолютно окреме закрите майкрософтовское чари, сильно виходить за рамки протоколу HTTP. Ну а ми зосередимося саме на ньому. І тут же підійдемо до наступної проблеми.

Вже є зрозумілий сценарій роботи — в будь незрозумілої ситуації відправляй користувача на сервер авторизації, нехай той вирішить що з ним робити і поверне готову відповідь. Але як саме сервер авторизації розповість тому, чи іншому серверу про те, що користувач авторизований? Тут ми знову повертаємося до ідей пункту першого, а саме — до сесійного ключа. Повернемося до витоків: наявність сесійного ключа — ознака авторизованності, сам сесійний ключ відмикає двері до інформації про користувача, і, ви не повірите, до інформації про сесію. Значить сервер авторизації авторизує і віддає сесійний ключ іншого сервера.

Тепер, правда, він називається вже не сесійний ключ, а токен.
А точніше кажучи (по протоколу OAuth 2.0, поверх якого написаний OpenID Connect) це відразу два токена — Access Token, щоб чіпляти його до всіх запитів як діди чіпляли ключі сесії, і Refresh Token, щоб оновлювати Access Token коли він протухне.

Підведемо проміжний підсумок. Замість того щоб запитати у користувача логін і пароль, сервер відправляє його на інший сервер, окремий сервер авторизації. Той робить всю роботу, і потім віддає першому токени. У точності за цим сценарієм можна використовувати додатки, мобільні і іноді десктопні., Тільки ніяких редиректів вони не роблять, просто відправляють сервера авторизації JSON з логіном і паролем, а той надсилає їм токени у відповідь.

В Мобільних і десктопних додаткахтак можна. Вони чомусь вважаються безпечніше веба, а ось у веба життя складніше.

6. З одного боку, не складніше, а навпаки простіше. Можна зробити редирект і не возитися самому з промальовкою логіно-парольних форм. З іншого боку — дуже, дуже не хочеться тягати токени через браузер у відкритому вигляді. Це майже так само огидно небезпечно як не зашифрований пароль в access Basic authentication. Адже ніхто не хоче повторити ту стару страшну помилку.

Рішення проблеми знайшлося не сказати щоб дуже витончене, але робоче. Спочатку все йде як зазвичай, перехід на авторизацію, власне авторизація. Потім, коли настає час повернутися назад з токенами відбувається зворотній редирект. Але замість токенів адресою повернення чіпляється одноразовий код. Одноразовий код тільки що породжений сервером авторизації тільки для цього конкретного моменту. У нього дуже малий час життя. Ледь отримавши одноразовий код інший сервер повинен підштовхнути спідниці, выпучить очі та терміново вирушати на сервер авторизації знову — щоб за одноразовим кодом таки отримати жадані токени.

Читайте також  Криптографія після висадки інопланетян

Для походу з кодом за токенами на сервері авторизації є спеціальний ресурс. Приймає він, по специфікації, вже не GET, а POST. Що ніби натякає нам, що робити цей запит потрібно не з браузера, а з сервера на сервер.

З цієї ж причини на будь-якому поважаючому себе сервері авторизації CORS для POST запитів заборонений.

7. До речі, ви ще пам’ятаєте про аутентифікацію і авторизацію? Аутентифікація — це коли когось просто пускають по логіну і паролю, або не пускають. А авторизація — це коли вже пустивши, починають розбиратися кого ж саме пустили.

А пам’ятаєте про OAuth 2.0? Я згадував його пару разів вище, як якийсь фундамент для OpenID Connect.

А пам’ятаєте про OpenID Connect?

Так от, OAuth 2.0 — це аутентифікація. Вся описана раніше злегка заплутана процедура з трьома учасниками, паролем кодом і токеном — це все про аутентифікацію, просто про те щоб когось запустити кудись. Протокол OAuth 2.0.

OpenID Connect ж — це авторизація. Тобто до OAuth він додає ті частини, де з’ясовується кого пустили.

Для цього в список токенів додається ще один, називається він ID Token. Ті хто пройшов по посиланню, можливо, здивовані, не зустрівши в ній нічого ні про який ID Token. Нехай диво не переходить у переляк, ID Token це і є JWT, повертається як base64-encoded матрьошка в тому ж JSON, що і Access Token і Refresh Token. У будь-якому випадку, все що ви хотіли знати про користувача в ньому.

І ще є спеціальний ресурс авторизації на сервері під назвою userinfo, куди можна стукнутися з Access Token, і отримати у відповідь той же JSON, що і в ID Token. Тільки навіщо він потрібен, якщо ID Token вже є? Питання до авторів спеки.

Також OpenID Connect містить опис різних полів інформації про користувача. Того, як можна цю інформацію отримати, прямо під час авторизації або в будь-який момент після. І опис того, як і коли користувач дозволить вам користуватися цією інформацією.
Чи не дозволити. Ось так, коротко, і влаштований OpenID Connect 1.0.

8. Трошки мішури в протоколі. Сподіваюся, що ви достатньо втомилися від прочитання статті на даний момент, щоб не приділяти цьому пункту багато уваги, просто пробігши його очима. Тут я згадаю параметри, які в специфікації є, і вони несуть певне смислове навантаження, але до реалізації самої ідеї безпосередньо не відносяться. В основному вони додають безпеки, ну, або просто дозволяють передати якусь інформацію від одного з учасників процесу іншого, при необхідності.

Читайте також  Перед вами — React Modern Web App

Client ID Client Secret. Client мовою протоколу OpenID Connect це зовсім не браузер, а той самий інший сервер, до якого потрібно авторизувати користувача. Припустимо, у вас є сайт і ви хочете прикрутити до нього модну авторизацію через фейсбук. І через гугол. І вже не таку модну через твіттер. Реалізувати в коді протокол буде не достатньо. Вам ще потрібно буде зареєструватися в фейсбуці, і в гуглі, і в твіттері, але не в якості користувача, а в якості того самого клієнта, який, як сервер, може користуватися їх авторизацією. При реєстрації ви отримаєте від умовного фейсбуку Client ID Client Secret. І при запиті авторизації серед іншого відправите Client ID. А коли підете з одноразовим кодом за токеном від вас ще й Client Secret зажадають.

Redirect URI. Тут все просто. Відправляючи користувача на умовний фейсбук авторизовуватись, потрібно повідомити фейсбуку куди йому повертати коди і токени після авторизації. Звичайно, ви все одно передаєте йому свій Client ID. Але окремий Redirect URI дозволяє перекидати після авторизації різних користувачів на різні сторінки, наприклад адмінів на адмінку, а рядових користувачів на їх персональні сторінки. Практично. До того ж, прописаний в налаштуваннях клієнта на умовному фейсбуці дозволений список можливих Redirect URI це додаткова безпека.

Scope. Це список того що сервер хоче дізнатися про користувача від сервера авторизації. Значення у списку розділені пробілами, openid серед них має бути обов’язково, а далі читайте специфікацію.

State. Пам’ятайте про одноразовий код, за яким видаються токени, як талончик в електронній черзі? Так от, state — це code навпаки, якщо code сервер авторизації видає іншого сервера щоб той його незабаром повернув, той state інший сервер видає сервера авторизації щоб той повернув його при редірект. Потрібен він, наскільки я розумію, у разі якщо інший сервер вже встиг створити свою власну сесію, щоб вона у всіх цих редиректах не загубилася.

Є ще інші параметри, типу запиту авторизації і часу життя токенів, але щоб зрозуміти навіщо я вам не потрібен.

На завершення. Дуже сподіваюся, що не дуже вдумливе і зосереджене читання тексту вище десь допомогло вам вловити ідеї, що лежать в основі деяких сучасних протоколів розмежування доступу. Але приступаючи до реалізації, або просто налаштування якогось-небудь з них,  знайдіть хороший туторіал, та ретельно дотримуйтесь і кожному слову і кожній букві. А розуміння ідей нехай розбудить у вас і інтуїцію. А інтуїція хай клює вас в тім’я кожен раз, коли ви упустите якийсь не такий істотний, на перший погляд параметр або налаштування, і залишите цю дірочку для спітнілих пустотливих рученят.

 

Пам’ятайте, що це все таки безпека, і її правила, якими б дурними і безглуздими вони не здавалися, писані кров’ю. Ну, може не зовсім кров’ю, це не техніка безпеки у ливарному цеху, в кінці кінців, але грошима та репутацією точно, а гроші і репутація теж не ті штуки, якими варто розкидатися запросто так.

Степан Лютий

Обожнюю технології в сучасному світі. Хоча частенько і замислююся над тим, як далеко вони нас заведуть. Не те, щоб я прям і знаюся на ядрах, пікселях, коллайдерах і інших парсеках. Просто приходжу в захват від того, що може в творчому пориві вигадати людський розум.

You may also like...

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *