Дослідження Single Sign-On: реалізація, плюси, мінуси і ключові особливості

Технологія Single Sign-on автоматично логінить користувача в декількох різних застосунках чи сайтах після введення логіну та пароля лише в одному з них. Вона полегшує життя девелоперам, які налаштовують авторизацію та автентифікацію для корпоративних застосунків, сисадмінам і всім інтернет-юзерам.

Я Владислав Головко, Node.js developer у DataArt, займаюся веброзробкою вже 23 роки. Кодив на Perl і PHP, зараз — на Node та React. У своїй статті детально зупинився на чотирьох способах реалізації SSO, їхніх ключових моментах, плюсах і мінусах.

Як SSO полегшує нам життя

Одна з головних ознак SSO — коли під час логіну нас перекидає на інший сайт, де відбувається автентифікація. Так працюють, наприклад, усі застосунки Google і Office Online (Microsoft 365). У Slack спосіб логіну трохи відрізняється — потрібно попередньо ввести корпоративний піддомен (це і є сайт, де відбувається автентифікація), натиснути «Continue» та опинитись у своєму обліковому записі — але це теж SSO.

SSO заощаджує нам час (і нерви), а нашим компаніям і клієнтам, відповідно, гроші, наприклад:

  • Допомагає швидко залогінитись у всі робочі інструменти, ввівши логін і пароль лише в одному з них — економить час на згадування та відновлення паролів.
  • Скорочує час роботи системного адміністратора на створення, а потім і видалення облікових записів кожного співробітника.
  • Робить зручнішим життя кожного інтернет-юзера завдяки можливості реєстрації на безлічі сайтів через обліковий запис у Google або соцмережах.

Розглянемо чотири способи реалізації SSO, їхні плюси, мінуси і ключові особливості.

Субдомени та cookie

Це найпростіший варіант. У нас є куки, є спільний домен — відповідно, всі піддомени нас впізнають, все просто і зрозуміло. Саме цим шляхом пішов Google: всі його застосунки знаходяться на його домені, перехід з одного застосунка в інший відбувається плавно й непомітно, без редиректів тощо.

Плюси методу:

  • Все дуже просто, не потрібні жодні протоколи, ми просто використовуємо кукі.
  • Це SSO з коробки, просто за визначенням.

Але звідси випливають і мінуси:

  • Такий SSO обмежений кільцем субдоменів, і жоден інший домен не може отримати доступ до нашого кукі.
  • Весь user management лягає на плечі веброзробника: вибрати функцію хешування паролів, вирішити, як складати дані в базу, як організувати відновлення, зміну паролів і підтвердження e-mail.
  • Немає стандартного формату і шляху отримання профілю користувача. На одному субдомені в нас може бути застосунок на PHP, на іншому — на Java тощо. Щоб витягнути профіль користувача на PHP, потрібно звертатися до бази даних засобами PHP, для профілю на Java — засобами Java. Все абсолютно кастомне і залежить від нас, це далеко не найзручніший варіант.

Тепер перейдемо до стандартів.

Kerberos

Це протокол мережевої автентифікації, що був розроблений у 70-х Массачусетським інститутом, а в 90-х набув свого сучасного вигляду — Kerberos 5. У 2000-х Microsoft зробили його домашнім протоколом автентифікації у своєму домені.

Аутентифікація у вебзастосунку відбувається за допомогою протоколу HTTP. Kerberos використовує Authentication scheme: Negotiate.

На відміну від найпростіших видів HTTP-автентифікації (plain, digest), тут, крім двох учасників процесу, сервера і клієнта (юзера), з’являється третій — key distribution center (KDC). Він виступає тут як суддя. Відповідно, користувач і сервер мають йому довіряти.

Kerberos починає працювати, коли ми вмикаємо комп’ютер і логінимось у Windows. Йде звернення до KDC, він видає TGT-токен, який повідомляє, що ми автентифіковані в системі. Цей токен кладеться в кеш операційної системи, і всі юзери, які хочуть працювати з ресурсами Kerberos, мають до нього доступ.

Як це працює з застосунками? Ми заходимо у Windows і звертаємося браузером до застосунку, який є частиною домену Windows. Вебсервер надсилає нам у відповідь 401 Authorization Negotiate. Браузер (наприклад, Edge або Google Chrome) має вбудований клієнт Kerberos.

Коли у відповіді приходить 401 Authorization Negotiate, він звертається до кешу ОС, бере цей TGT-токен і запитує в KDC другий тікет для роботи з конкретним веб-сервісом. KDC видає другий токен, браузер передає його в header Authorization і надсилає на сервер. Сервер приймає, дивиться, верифікує, і якщо все добре, відповідає: «200 ОК». Так ми отримуємо доступ до вашого застосунку без жодних логінів і паролів.

Плюси:

  • Це SSO за визначенням, із коробки.
  • Завдяки численному шифруванню, може працювати не лише за https, а й за http.
  • Взаємна автентифікація. Користувач знає, що сервер реальний, а сервер — що запит прийшов від цього користувача.
  • Працює з коробки у Windows. Якщо ви працюєте на Windows, то вам практично нічого не потрібно налаштовувати, навіть у браузері є вбудований клієнт Kerberos.
  • У разі проблем автоматично даунгрейдиться до NTLM.
    Наприклад, сайт чи застосунок є частиною домену Windows, але доступний і з інтернету. Якщо ми спробуємо звернутися до них, не будучи залогіненими в домен, то в нас не буде TGT-тікета й, відповідно, з Kerberos ми працювати не зможемо.
    Тоді сервер спробує «поговорити» з нами за допомогою протоколу NTLM, попередником Kerberos, він простіше, у ньому беруть участь лише сервер і клієнт. Сервер автентифікує користувача за тією самою базою даних (у цьому випадку, найімовірніше, Active-directory), а не за простим файлом з паролями, як у Authorization basic.
    Так ми можемо отримати доступ до ресурсу ззовні — ми не входимо в домен, але маємо запасний спосіб отримати доступ до нашого ресурсу. Звісно, SSO в цьому випадку не буде — кожен ресурс проситиме вас вводити логін і пароль (хоча це будуть одні і ті самі логін і пароль).
  • Розробнику застосунку не потрібно нічого робити, він не бере участі в роботі Kerberos. Все відбувається на нижчому рівні — на рівні мережі та сервісів.

Мінуси:

  • Intranet та домен Windows — ми обмежені внутрішньою мережею або доменом Windows.
  • Низькорівневий протокол. Це більше робота адмінів, ніж веброзробників.
  • Немає стандартних шляхів доступу до профілю користувача або його формату.

Те, що розробнику не потрібно нічого робити, є насправді як плюсом, так і мінусом. Ми не маємо стандартних інструментів, щоб отримати доступ до дозволів і профілю користувача — автентифікація відбувається на нижчому рівні. Єдине, до чого ми маємо доступ — це header, з якого ми можемо дістати username та ім’я домену.

Security Assertion Markup Language (SAML)

Протокол SAML — стандарт обміну автентифікаційною та авторизаційною інформацією у форматі XML. Весь обмін даними відбувається за HTTP, отже, веброзробники є повноправними учасниками процесу.

Як і в Kerberos, тут троє учасників процесу:

  • User;
  • Identity provider — система, яка нас автентифікує;
  • Service provider — сайт або система, куди ми хочемо увійти.

Як працює ця схема? Ми звертаємося до сервіс-провайдера, він бачить, що ми не автентифіковані, та надсилає SAML authorization request до identity-провайдера через редірект у браузері. Якщо ми ще не залогінені, identity-провайдер видає форму логіна і пароля, ми аутентифікуємось.

Тільки-но він підтвердив нашу іdentity, він звертається назад до service-провайдера з запитом, у якому міститься звичайна HTML-форма з SAML-токеном (XML з нашими даними). Ця форма автоматично сабмітиться браузером за подією завантаження HTML-документа («window.onload = formSubmit»).

Нижче приклад такого XML. Розглянемо, з чого він складається та як працює.

Ключові моменти:

1. Assertions — набори XML елементів.

2. Bindings — спосіб, яким ми пересилаємо XML між серверами. Це може бути:

  • Redirect — HTTP-редирект дозволяє передавати повідомлення протоколу SAML у параметрах URL-адреси. Тобто XML інкапсулюється у query string.
  • HTTP POST Binding — XML знаходиться всередині форми як один з її параметрів.
  • SAML SOAP Binding — так, навіть у SOAP є варіант спілкування між сервіс-провайдерами та identity-провайдерами.

3. Протоколи — способи всіх комунікацій між серверами, внаслідок яких ми отримуємо наш XML. Це може бути:

  • Тільки redirect.
  • Redirect + POST-форма.
  • Redirect + SOAP-запит.

4. Профілі — use кейси протоколу SAML. SAML має багато профілів, але насправді в 99% випадків він використовується тільки для SSO.

5. Метадані — містять всю необхідну інформацію для налаштування інтеграції між identity-провайдером і сервіс-провайдером: URL, сертифікати тощо.

Плюси:

  • Це стандарт.
  • Є взаємна автентифікація. Під час надсилання повідомлень один одному сервіс-провайдер і identity-провайдер можуть підписувати їх своїми сертифікатами. Так одержувач повідомлення може бути впевненим, що воно справжнє й актуальне.
  • Кросплатформність — ми можемо використовувати будь-яку ОС.
  • Стандартний формат профілю користувача, у цьому випадку XML.
  • Кращий User Experience. Користувач завжди автентифікується на одному звичному сайті, enterprise identity provider, якому довіряє. І має один логін і пароль — усе дуже зручно.
  • XML — human-readable формат. У ньому ми можемо легко прочитати всі дані.
  • Розробник не несе відповідальності за user management. Це є обов’язком identity-провайдера. На його боці відбувається автентифікація, відновлення, хешування паролів тощо.

Мінуси:

  • XML може бути великим. У ньому дуже багато надмірної інформації.
  • POST binding не дуже підходить для нативних програм.

Припустимо, ми маємо нативний застосунок на iOS і хочемо автентифікуватися за SAML. Найімовірніше, ми відкриваємо зовнішній браузер, він переходить на сервер identity-провайдера, де ми вводимо логін і пароль та аутентифікуємось. У зворотний бік identity-провайдер має надіслати POST-запит із формою на URL нашого сервіс-провайдера.

Якщо наш застосунок є нативним, ми не маємо сервера (сервіс-провайдером є аплікейшн). У такому разі щоб мати можливість отримати дані автентифікації, identity-провайдеру як зворотна адреса передається URL з префіксом кастомного протоколу, а не http://.

Наприклад, myapp://. Отримавши такий URL, операційна система знає, що вона має запустити застосунок, а не робити http запит на сервер. Так застосунок отримує доступ до рядка URL і всієї інформації, що він містить. Проте під час використання POST-запиту необхідний нам XML токен знаходиться не в URL, а в тілі запиту, доступу до якого застосунок не має. Таким чином автентифікація не спрацює.

Як так вийшло, що SAML — не найкращий варіант для нативних програм? Справа в тому, що SAML 2 (найновіша версія протоколу SAML), була випущена ще 2005 року, а перший айфон — 2007-го. Під час написання протоколу таких юзкейсів ще не було.

OpenID Connect (OIDC)

Це надбудова над протоколом OAuth2, яка працює за його допомогою.

Перед описом процесу важливо розділити поняття автентифікації й авторизації та познайомитися з OAuth2.

Автентифікація:

  • Підтверджує нашу особу.
  • Може бути виконана за допомогою OpenID Connect.
  • Результат аутентифікації — ID Token.

Авторизація:

  • Повідомляє, що ми можемо робити, а що — ні, до чого маємо доступ, до чого — ні.
  • Може бути виконана за допомогою протоколу OAuth2.
  • Результат авторизації — Access Token.

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

OAuth2

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

Здається, зручно, але передача логіна й пароля від пошти іншому сайту не виглядає як щось безпечне, навіть якщо там не планують його зберігати. Теоретично Linkedin міг зробити з вашою поштою все, що завгодно, зокрема почати писати листи від вашого імені.

Так виникла потреба створити новий протокол.

З’явився OAuth2 — авторизаційний framework, що дозволяє надавати стороннім застосункам обмежений доступ до ваших даних без передачі креденшіалс.

Результат його роботи — consent screen — з’являється, коли застосунок на іншому ресурсі запитує доступ до наших даних, наприклад, електронної пошти, імені та фото на Facebook чи Linkedin. Один із прикладів, навіщо це потрібно — для сайтів, які можуть на основі даних із LinkedIn зробити гарне, професійне резюме.

Але насправді такі програми можуть вимагати доступ до роботи з будь-якими даними з того ж LinkedIn, причому не лише на читання, а й на запис. І якщо на consent screen ми натиснемо «Allow», цей застосунок зможе робити публікації від нашого імені, видаляти наші публікації тощо.

Тепер подивимось, як це працює. Тут уже чотири учасники процесу:

  • Client — застосунок, що хоче отримати доступ до ваших даних.
  • Resource owner — користувач, що володіє даними (ми).
  • Authorization server, що видає токен та надає доступ до даних.
  • Resource server, що надає дані на API.

У той час, коли створювався SAML, не було поділу на дані та їхнє подання, сервер повертав нам цілком сформовані HTML-сторінки. Тобто не існувало стандартного способу відобразити дані з одного сайту в дизайні іншого. (У випадку SAML клієнт і ресурсний сервер є одним цілим.)

З появою SPA (single-page application) і API з’явилася можливість розділити ці два поняття. Тепер ми можемо підключити сотні SPA до одного сервера з даними та відображати одні й ті самі дані в різних дизайнах.

Схема отримання токена є майже такою самою, як у SAML. Ми звертаємося до затосунку, він бачить, що ми не автентифіковані, та перенаправляє нас на авторизаційний сервер. Ми вводимо логін і пароль, сервер нас автентифікує та повертає застосунку токен. Застосунок за допомогою header Authorization bearer підставляє туди токен і працює з ресурсним сервером.

Ключові моменти:

1. Реєстрація

Клієнтський застосунок, що працює з даними, має бути зареєстрованим на авторизаційному сервері, щоб сервер розумів, хто до нього звертається за токеном.

Плюс із Client_id авторизаційний сервер знає зворотну адресу (redirect_url), куди потрібно вислати токен. URL може бути кілька — ми можемо використовувати один і той самий Client_id для різних сайтів і доменів, просто прописавши декілька різних редиректів.

2. Scope

Це дозволи, які потрібні клієнтському застосунку для роботи з нашими даними: доступ до імейла, фото тощо. Це просто рядки, розділені пробілом.

3. Authorization flows

Це способи отримання токена, вони виконують ту саму роль, що і протоколи SAML. Їх існує величезна кількість, оскільки це фреймворк. Є навіть флоу для отримання токена для девайсів, що не мають ані клавіатури, ані миші, наприклад, для спілкування зі Smart TV за допомогою OAuth2.

4. Access token

Це результат спілкування між усіма цими серверами, що використовується для передачі серверу наших дозволів. Access-токени бувають у форматі простого рядку (некого хешу) або у форматі JWT (JSON web token).

5. Refresh token

Необхідний для отримання нового access-токена (коли термін дії попереднього скінчився). Access-токен — за визначенням bearer, тобто нашому ресурсному серверу однаково, хто прийде до нього з токеном.

Якщо ви отримали чийсь токен, діючи швидко (поки не скінчився термін його дії), ви можете отримати доступ до чужих даних — сервер не перевіряє, хто надіслав йому цей токен, головне, щоб токен був справжнім і актуальним. Відповідно, час життя access-токена має бути досить коротким — півгодини, година чи дві.

Ми маємо два варіанти отримати новий access-токен:

  1. Ми власноруч повторюємо всю операцію з браузерами, редиректами тощо.
  2. Програма, маючи refresh token, без нашої участі надсилає запити на endpoint (/oauth2/token) на авторизаційному сервері, отримує у відповідь новий access-токен і продовжує працювати.

Нарешті переходимо до OpenID Connect — рівня автентифікації поверх OAuth2. Він працює в парі з OAuth2 та відповідає за автентифікацію.

Вся магія лише в тому, що в scope ми маємо прописати permission — OpenID, повідомивши таким чином, що у відповідь ми чекаємо не лише access-токен, а й ID-токен.

На схемі — приклад одного з найпопулярніших authorization flow. Це authorization code grant, коли ми отримуємо токен за два проходи:

  1. Ми звертаємося до авторизаційного сервера, вводимо логін і пароль, він нас аутентифікує і за допомогою редиректу (тобто у query string) повертає код, а не токен.
  2. Наш сервер може звернутися backend-каналом до спеціального token endpoint на авторизаційному сервері, передати йому код і client_secret та отримати у відповідь access-токен.

Якщо при цьому ми ще й передали у scope OpenID, то у відповідь отримаємо JSON, що містить ID-токен і access-токен.

ID-токен потрібний для отримання інформації про самого користувача (профіль користувача), а не про дані, що йому належать. На відміну від access-токена (який може бути просто хеш-рядком), ID-токен завжди форматований як JWT.

Формат JWT

Це JSON, закодований за допомогою Base64 для передачі мережею. Він складається з трьох частин:

  1. Header, де ми вказуємо тип шифрування, який використовується для підпису.
  2. Payload — корисні дані, вся інформація про нас.
  3. Підпис.

На сайті JWT є чудовий опис формату, можна пограти з різними варіантами токенів. Ви можете вставити будь-який токен (вони не зашифровані) у форму на сайті та побачити весь його вміст.

Наприклад, тут sub — це subject, якому було видано токен. Це унікальний ID користувача, name тощо; Iat — це issued at, час видачі токена. У стандарті описано певну кількість стандартних полів, але ми також можемо додавати власні.

Плюси:

  • Це стандарт.
  • Взаємна автентифікація.
  • Кросплатформність — ми можемо використовувати будь-яку ОС.
  • Стандартний формат user profile.
  • Покращує UX завдяки роботі з надійним сервером автентифікації.
  • Маленький розмір токена — його можна передати в URL. Не обов’язково використовувати для цього POST-форму.
  • Чудова робота з нативними застосунками.
  • Широке розповсюдження завдяки соцмережам.

Завдяки його простоті, безліч сервісів (Facebook, Linkedin, Google, Github тощо) вибрали як протокол аутентифікації саме OIDC, а не SAML. Microsoft також вибрав цей протокол для свого SSO.

Нюанси:

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

  • OAuth2 працює тільки через HTTPS.
  • JWT token за визначенням не можна відкликати. У ньому міститься вся необхідна інформація для перевірки валідності. Таким чином, поки термін дії токена не закінчився, всі сервери, що працюють з ним, будуть чесно віддавати вам дані. Проте зараз уже існують деякі напрацювання щодо можливості відкликання токена.

Як впровадити SSO

І це найкоротший пункт моєї статті. Чудова новина в тому, що писати й винаходити самостійно нам нічого не потрібно. Є безліч сервісів, що допомагають налаштувати SSO практично за будь-яким протоколом у кілька кліків, як-от Auth0, Amazon Cognito, Firebase, onelogin тощо.

Мінуси SSO:

SSO — чудова і зручна технологія, але й вона має свої мінуси:

  • Наявність лише одного сервера з одним логіном і паролем є як головним плюсом SSO, так і його головним мінусом. Той, хто вкраде наші креденшіалс, отримає доступ одразу до всіх наших застосунків.
  • Залежність від identity-провайдера. Якщо він дає збій, ми втрачаємо доступ до всіх програм і в компанії зупиняється робота.
  • Відсутність доступу до соцмереж у деяких країнах. Якщо ми надаємо доступ до сайту чи застосунку через соцмережі, ним не зможуть користуватися юзери з країн, де ці соцмережі заборонені.

Знаючи ці мінуси, важливо приділяти належну увагу безпеці та відповідально підходити до вибору identity provider — і все вийде. Вірю, що колеги і без мого нагадування дбають про безпеку й обирають лише надійні перевірені сервіси. Тож можу з упевненістю рекомендувати технологію SSO.

👍ПодобаєтьсяСподобалось22
До обраногоВ обраному13
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
некого хешу -> певного/якогось хешу

Не дуже шарю в цьому, але завжди було цікаво чи є сенс використовувати щось крім Firebase Authentication (або Amazon Cognito)?

Це ж як завжди — на смак та на колір, кому що подобається, а зміст приблизно однаковий )

Дякую за статтю! Напишу свій досвід впровадження SSO через SAML.

SAML це найбільш стандартний варіант, котрий вимагають великі компанії. OAuth2 теж використовують, але наявність SAML — це прям ключовий пункт, коли ви починаєте говорити з потенційним клієнтом. Бо це і Okta і Google GSuite і Azure AD та інші.

А по-друге, я не знайшов сервісів які підтримують SAML на рівні «налаштував і клікнув». Ми спершу працювали з Auth0 — але їх не самий дешевий план мав лише 3 enterprise connections. Тобто тільки 3 SAML клієнта. Ми провели бесіду з їх сапортом і все що вони могли нам запропонувати — платити щось типу 10К$ в рік за SAML підтримку. Тим більше їх SAML був досить костильним — кожного клієнта треба було підключати вручну через адмін панель Auth0. Альтернативи і конкуренти виглядали досить ненадійними, плюс зав’язуватись на іще одного провайдера, який міг в будь-який момент видати прайс на чотири нулі було ризиковано.

Тому прийшлось написати самому SAML реалізацію. Додати інтерфейс, щоб клієнт міг завантажити сертифікат, всі поля і т.п. Власне, я задоволений як вона працює. Але дуже не задоволений, що прийшлось в цьому розбиратись =))

Зате у нас уже є SAML, повноціння документація і користувачі ним користуються docs.testomat.io/integration/sso

я не знайшов сервісів які підтримують SAML на рівні «налаштував і клікнув»

Ну от саме з Auth0 налаштування зрозуміле і досить просте, проблем не було. Кількість кліентів, то інша історія — на ентерпрайз плані будь ласочка скільки завгодно ))

Але дуже не задоволений, що прийшлось в цьому розбиратись

Та навпаки ж чудово коли ти розуміеш як воно працює, завдяки цьому ще й доку класну написали!

1. У вас э гроші на ентерпрайз план? В мене ні (
2. Насправді, я волів би не знати цієї фігні, а платити 100 баксів в місяць сервісу який би це реалізував замість мене. Але на жаль (

Дякую за класний опис і розбір теми!

Тільки так і не зрозумів, чи Active Directory це частина Kerberos, чи щось окреме?
Також не згадали про LDAP.

Навпаки, Kerberos це частина Active Directory.
Тобто колись Microsoft вирішив «а давайте зберемо Kerberos + LDAP + щось інше до купи і буде у нас своя authentication + authorization»

До речи, Kerberos, можна і в тому ж Linux використовувати, як окремий пакет, якій ніякого відношення до Active Directory. не має

LDAP до SSO прямого відношення не має, це просто іерархічна БД, тобто користувачив і все інше можно и в звичайной БД зберігати, але в деякіх випадках LDAP краще.

SAML це також майже частина AD, для цього потрібен додатково підняти ADFS, і вже на ньому конфігурувати SP