RESTful аутентифікація


745

Що означає RESTful Authentication і як це працює? Я не можу знайти хороший огляд в Google. Я розумію лише те, що ви передаєте ключ сеансу (ребераль) в URL, але це може бути жахливо неправильним.


3
Коли я перебуваю в Google Restful Authentication, я знаходжу десяток плагінів RoR. Я припускаю, що це НЕ те, що ви шукаєте. Якщо не RoR, то яка мова? Який веб-сервер?
С.Лотт

2
Це не буде жахливо неправильно, якщо ви використовуєте HTTPS. Повний HTTP-запит разом із URL-адресою буде зашифровано.
Бхарат Хатрі

4
@BharatKhatri: Так. Я ніколи не передаватиму конфіденційну інформацію в URL-адресу, видиму користувачеві. Ця інформація набагато частіше витікає для практичних цілей. HTTPS не може допомогти у випадку випадкового витоку.
Jo So

2
@jcoffland: Що ви маєте на увазі під реальною RESTful аутентифікацією? Мені цікаво, оскільки я щойно реалізував третій спосіб із прийнятої відповіді, проте я не задоволений цим (мені не подобається додатковий парам в URL).
BlueLettuce16

4
деякі люди використовують jwt.io/introduction для вирішення цього питання. Я зараз про це займаюся дослідженням, щоб вирішити свою справу: stackoverflow.com/questions/36974163/… >> Сподіваюся, це буде добре.
тоха

Відповіді:


586

Як обробляти автентифікацію в архітектурі RESTful Client-Server - це питання дискусії.

Зазвичай це може бути досягнуто у світі SOA через HTTP за допомогою:

  • HTTP базовий auth через HTTPS;
  • Файли cookie та управління сеансами;
  • Позначення в заголовках HTTP (наприклад, OAuth 2.0 + JWT);
  • Перевірка автентичності з додатковими параметрами підпису.

Вам доведеться адаптувати або навіть краще змішати ці методи, щоб найкраще відповідати вашій архітектурі програмного забезпечення.

Кожна схема аутентифікації має свої PRO та CON, залежно від мети вашої політики безпеки та архітектури програмного забезпечення.

Базовий протокол HTTP через HTTPS

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

GET /spec.html HTTP/1.1
Host: www.example.org
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

Це легко здійснити, доступний за замовчуванням у всіх браузерах, але має деякі відомі недоліки, наприклад, жахливе вікно автентифікації, відображене в браузері, яке зберігатиметься (тут немає функції, схожої на LogOut), деяке додаткове споживання процесора на стороні сервера, і той факт, що ім’я користувача та пароль передаються (через HTTPS) на Сервер (слід бути більш захищеним, щоб пароль залишався лише на стороні клієнта під час введення на клавіатурі та зберігався як захищений хеш на сервері) .

Ми можемо використовувати дайджест аутентифікації , але він також вимагає HTTPS, оскільки він уразливий для атак MiM або Replay і специфічний для HTTP.

Сесія через куки

Якщо чесно, сеанс, керований на сервері, не справді без громадянства.

Однією з можливостей може бути збереження всіх даних у вмісті файлів cookie. І, за задумом, файл cookie обробляється на стороні Сервера (Клієнт насправді навіть не намагається інтерпретувати дані файлів cookie: він просто повертає його назад на сервер при кожному наступному запиті). Але ці файли cookie є даними про стан додатків, тому клієнт повинен керувати ними, а не сервером у чистому світі без громадянства.

GET /spec.html HTTP/1.1
Host: www.example.org
Cookie: theme=light; sessionToken=abc123

Сама техніка файлів cookie пов'язана з HTTP, тому вона не є справді RESTful, яка повинна бути незалежною від протоколу, IMHO. Він уразливий для атак MiM або Replay .

Надано через Token (OAuth2)

Альтернативно - помістити маркер у заголовки HTTP, щоб запит був аутентифікований. Так, наприклад, робить OAuth 2.0. Дивіться RFC 6749 :

 GET /resource/1 HTTP/1.1
 Host: example.com
 Authorization: Bearer mF_9.B5f-4.1JqM

Коротше кажучи, це дуже схоже на файл cookie і страждає від одних і тих самих питань: не без громадянства, покладаючись на деталі передачі HTTP, і з урахуванням багатьох недоліків у безпеці - включаючи MiM та Replay - тому слід використовувати лише через HTTPS. Зазвичай JWT використовується як маркер.

Перевірка автентичності

Автентифікація запитів полягає у підписанні кожного запиту RESTful через деякі додаткові параметри URI. Дивіться цю посилальну статтю .

У цій статті було визначено як таке:

Усі REST-запити повинні бути аутентифіковані, підписуючи параметри запиту, відсортовані в нижньому регістрі, в алфавітному порядку, використовуючи приватний обліковий запис як маркер підписання. Підписання має відбуватися перед URL-кодуванням рядка запиту.

Ця методика, можливо, є більш сумісною з архітектурою без стану, і також може бути реалізована за допомогою легкого управління сеансами (використовуючи сеанси в пам'яті замість стійкості БД).

Наприклад, ось загальний зразок URI за посиланням вище:

GET /object?apiKey=Qwerty2010

має передаватися як таке:

GET /object?timestamp=1261496500&apiKey=Qwerty2010&signature=abcdef0123456789

Рядок, що підписується, є, /object?apikey=Qwerty2010&timestamp=1261496500а підпис - це хеш SHA256 цієї рядки з використанням приватного компонента ключа API.

Кешування даних на стороні сервера завжди може бути доступним. Наприклад, в нашій рамках ми кешуємо відповіді на рівні SQL, а не на рівні URI. Тому додавання цього додаткового параметра не порушує механізм кешування.

Дивіться цю статтю для отримання детальної інформації про RESTful аутентифікацію в нашій системі ORM / SOA / MVC клієнт-сервер, заснованої на JSON та REST. Оскільки ми дозволяємо спілкуватися не тільки через HTTP / 1.1, але також іменованими каналами або GDI-повідомленнями (локально), ми намагалися реалізувати справді схему аутентифікації RESTful, а не покладатися на специфіку HTTP (наприклад, заголовка чи куки).

Пізніша примітка : додавання підпису в URI можна сприймати як погану практику (оскільки, наприклад, вона з’явиться в журналах http-сервера), тому її необхідно пом'якшити, наприклад, належним TTL, щоб уникнути повторів. Але якщо ваші http-журнали будуть порушені, у вас, безумовно, виникнуть більші проблеми із безпекою.

На практиці майбутня аутентифікація токенів MAC для OAuth 2.0 може стати величезним покращенням стосовно поточної схеми "Надано токеном". Але ця робота все ще триває і пов'язана з передачею HTTP.

Висновок

Варто зробити висновок, що REST не лише на основі HTTP, навіть якщо на практиці він також здебільшого реалізований через HTTP. REST може використовувати інші шари зв'язку. Отже, RESTful аутентифікація - це не просто синонім автентифікації HTTP, незалежно від того, на що відповість Google. Він навіть не повинен використовувати механізм HTTP взагалі, але повинен бути абстрагований від рівня зв'язку. І якщо ви використовуєте HTTP-зв’язок, завдяки ініціативі Let Encrypt немає причин не використовувати належну HTTPS, яка потрібна на додаток до будь-якої схеми аутентифікації.


5
Якщо ви використовуєте Cookieяк кращу заміну, HTTP Basic Authви можете зробити справжню автентифікацію без стану за допомогою методу закінчення терміну автентифікації та можливості виходу з системи. Прикладом реалізації може бути використання файлу cookie, що Emulated-HTTP-Basic-Authмає схоже значення з реальним HTTP Basic Auth, а крім того, встановлений строк закінчується. Потім вихід може бути реалізований за допомогою видалення цього файлу cookie. Я думаю, що будь-який клієнт, здатний підтримувати HTTP Basic Auth, також може підтримувати автентифікацію файлів cookie, зроблених таким чином.
Мікко Ранталайнен

4
@MikkoRantalainen Але цим файлом cookie все одно керуватиме сервер, як я писав. Це якесь без громадянства, але не "чисте" без громадянства. У всіх випадках вам потрібен код JavaScript, призначений для входу / виходу з клієнта, що цілком можливо, наприклад, із HTTP Digest Auth - хороша ідея, але тут немає великої користі, щоб винаходити колесо.
Арно Бушез

4
Я б стверджував, що сервер реалізує інтерфейс користувача та логіку для налаштування заголовка, але сам заголовок без стану. Клієнт, призначений для API, може пропустити за допомогою довідки сервера для налаштування заголовка і просто передати необхідну інформацію, схожу на HTTP Basic Auth. Моя думка, що звичайні UA (браузери) настільки погано реалізують Basic Auth, що його не можна використовувати. CookieНатомість можна використовувати емуляцію, надану сервером для того ж самого матеріалу в іншому заголовку ( ).
Мікко Ранталайнен

6
Я думаю, що правильна відповідь - stackoverflow.com/questions/6068113/…
graffic

7
Потворне запит на пароль для авторизації HTTP з’явиться лише в тому випадку, якщо сервер вимагає цього, відсилаючи відповідь 401 Несанкціонований відповідь. Якщо вам це не подобається, просто надішліть замість нього 403 Заборонені. Сторінка помилок може містити спосіб входу або посилання на неї. Однак найбільший аргумент проти cookie AND http аутентифікації (незалежно від того, держава є стороною сервера чи клієнтом) - це те, що вони вразливі до підробок запитів на веб-сайті. З цієї причини найкращим підходом є спеціальна схема авторизації, власний заголовок авторизації або користувацький параметр GET або POST.
Dobes Vandermeer

418

Я сумніваюся, чи люди з ентузіазмом кричали "Аутентифікація HTTP" коли-небудь намагалися зробити додаток на базі браузера (замість веб-сервісу машина-машина) за допомогою REST (без правопорушень - я просто не думаю, що вони коли-небудь стикалися з ускладненнями) .

Проблеми, які я виявив при використанні автентифікації HTTP на сервісах RESTful, які створюють HTML-сторінки для перегляду в браузері:

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

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

Я вважаю, печиво - це рішення. Але зачекайте, печиво - це зло, чи не так? Ні, вони не такі, як часто використовуються файли cookie - це зло. Сам файл cookie - це лише інформація про клієнтську інформацію, подібно до інформації про автентифікацію HTTP, яку б браузер відстежував під час перегляду. І ця частина інформації на стороні клієнта надсилається на сервер при кожному запиті, знову так само, як і інформація про аутентифікацію HTTP. Концептуально єдиною відмінністю є те, що вміст цього фрагмента стану на стороні клієнта може визначатися сервером як частина його відповіді.

Здійснюючи сеанси ВІДКРИТИм ресурсом, дотримуючись наступних правил:

  • Сесія відображає ключ до ідентифікатора користувача (і , можливо, в останню екшен-мітку часу для тайм - ауту)
  • Якщо сеанс існує, то це означає, що ключ дійсний.
  • Увійти означає POSTing to / session, новий ключ встановлюється як cookie
  • Вихід означає DELETEing / session / {key} (із перевантаженим POST, пам’ятайте, що ми - браузер, а HTML 5 - ще довгий шлях)
  • Аутентифікація проводиться шляхом надсилання ключа у вигляді файлу cookie при кожному запиті та перевірки, чи існує сесія та чи дійсна вона

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

converter42 додає, що при використанні https (що ми повинні) важливо, щоб у файлу cookie встановлено захищений прапор, щоб інформація про автентифікацію ніколи не надсилалася через незахищене з'єднання. Чудова справа, я сам цього не бачив.

Я вважаю, що це достатньо рішення, яке добре працює, але мушу визнати, що мені недостатньо експерта з питань безпеки, щоб визначити потенційні дірки в цій схемі - все, що я знаю, це те, що сотні веб-додатків, які не є RESTful, використовують по суті те саме протокол входу ($ _SESSION в PHP, HttpSession в Java EE тощо). Вміст заголовка файлів cookie просто використовується для адреси ресурсу на сервері, подібно до того, як мова прийняття може використовуватися для доступу до ресурсів перекладу тощо. Я відчуваю, що це те саме, але, може, й інші? Як ви думаєте, хлопці?


68
Це прагматична відповідь і запропоноване рішення працює. Однак використання термінів "RESTful" і "session" в одному реченні є просто неправильним (якщо між ними також немає "not"). Іншими словами: будь-який веб-сервіс, який використовує сеанси, НЕ ВІДБУДОВА (за визначенням). Не зрозумійте мене неправильно - ви все ще можете використовувати це рішення (YMMV), але термін "RESTful" не може бути використаний для цього. Я рекомендую книгу O'Reilly про REST, яка дуже легко читається і глибоко пояснює тему.
johndodo

23
@skrebbel: чисте рішення REST надсилатиме дані автентифікації щоразу, коли він запитує ресурс, що є менш ніж досконалим (це робить HTTP Auth). Пропоноване рішення працює і є кращим для більшості випадків використання, але воно не RESTful. Немає необхідності у війні, я використовую і це рішення. Я просто не стверджую, що це RESTful. :)
johndodo

94
Ой, давай, подай приклад тоді. Що ще таке, що працює добре? Я щиро хотів би знати. HTTP Auth точно не є, ви не можете вийти без закриття веб-переглядача, і ви не можете запропонувати гідний UX для входу без безлічі сумісних для веб-переглядача, не сумісних JS. Мене не так хвилює "чисто RESTful" проти "майже RESTful" і ціла релігійна дискусія, але якщо ви скажете, що існує кілька способів, вам слід їх прописати.
skrebbel

15
По-справжньому ПОВЕРНЕНА автентифікація з агентами користувача реального світу (також "браузерами") складається з файлу cookie, що містить значення HTTP Authentication. Таким чином сервер може надати користувальницький інтерфейс для введення логіну та пароля, а сервер може змусити вийти (видаливши файл cookie). Крім того, замість відповіді 401 на необхідність входу в систему, коли аутентифікація не виконана, сервер повинен використовувати тимчасове переспрямування на екран входу, а після успішного входу використовувати тимчасове переадресація назад до попереднього місця. Крім того, сервер повинен вбудувати дію виходу (форма POST) майже на кожну сторінку для входу користувачів.
Мікко Ранталайнен

15
Я не бачу нічого поганого в використанні "спокійного" та "сеансу" в одному реченні, доки зрозуміло, що сеанс існує лише на стороні клієнта. Я не впевнений, чому така велика справа робиться щодо цієї концепції.
Джо Філіпс

140

Тут вже досить сказано на цю тему хорошими людьми. Але ось мої 2 копійки.

Існує 2 режими взаємодії:

  1. від людини до машини (HTM)
  2. від машини до машини (MTM)

Машина є загальним знаменником, вираженим як API REST, а суб'єкти / клієнти - люди чи машини.

Тепер, по-справжньому архітектурної архітектури, концепція безгромадянства передбачає, що всі відповідні стани заявки (маючи на увазі держави, що стоять перед клієнтом) повинні бути забезпечені кожним запитом. Під релевантним мається на увазі все, що вимагається API REST для обробки запиту та подання відповідної відповіді.

Якщо ми розглядаємо це в контексті програм "людина-машина", "заснованих на браузері", як вказує Скреббель вище, це означає, що (веб-додатку), що працює в браузері, потрібно буде надсилати свою інформацію та відповідну інформацію з кожним запитом це робить для REST API назад.

Враховуйте це: у вас є активна платформа REST API, що піддається впливу платформи даних / інформаційної платформи. Можливо, у вас є BI-платформа для самообслуговування, яка обробляє всі кубики даних. Але ви хочете, щоб ваші (людські) клієнти отримували доступ до цього через (1) веб-додаток, (2) мобільний додаток та (3) якесь стороннє додаток. Зрештою, навіть ланцюжок MTM веде до HTM - правильно. Тож користувачі людини залишаються на вершині інформаційного ланцюга.

У перших двох випадках у вас є справа про взаємодію людини з машиною, інформація фактично споживається користувачем людини. В останньому випадку у вас є машинна програма, що споживає API REST.

Поняття автентифікації застосовується в усьому світі. Як ви спроектуєте це так, щоб доступ до ваших API-програм REST отримував доступ однаково, захищено? Як я це бачу, є два способи:

Шлях-1:

  1. Для початку немає входу. Кожен запит виконує вхід
  2. Клієнт надсилає свої ідентифікаційні параметри + конкретні параметри запиту з кожним запитом
  3. API REST приймає їх, перевертає, записує в магазин користувачів (що б там не було) і підтверджує автентичність
  4. Якщо автор встановлений, надає запит; в іншому випадку відхиляє відповідний код статусу HTTP
  5. Повторіть вищезазначене для кожного запиту в усіх API REST у вашому каталозі

Шлях-2:

  1. Клієнт починає з запиту на аутентифікацію
  2. API REST для входу буде обробляти всі такі запити
  3. Він приймає параметри auth (ключ API, uid / pwd або що завгодно) і перевіряє автентифікацію щодо магазину користувачів (LDAP, AD або MySQL DB тощо)
  4. Якщо підтверджено, створює маркер аутентифікації та передає його назад клієнту / абоненту
  5. Потім абонент надсилає цей маркер авторизації + запит конкретних параметрів із кожним наступним запитом до інших бізнес-API REST, поки не вийдете з системи або поки термін оренди не закінчиться

Зрозуміло, що в Way-2 API REST знадобиться спосіб розпізнавання та довіри маркер як дійсний. API для входу здійснив перевірку автентичності, і тому "ключу valet" потрібно довіряти іншим API REST у вашому каталозі.

Це, звичайно, означає, що ключ / маркер автентичності потрібно буде зберігати та ділити між API REST. Це спільне сховане сховище токенів може бути локальним / федеративним будь-яким, що дозволяє API REST від інших організацій довіряти один одному.

Але я відволікаюсь.

Справа в тому, що "стан" (про статус автентифікованого клієнта) потрібно підтримувати та ділити, щоб усі API REST могли створити коло довіри. Якщо ми цього не робимо, а саме це Шлях-1, ми повинні прийняти, що для будь-якого / всіх запитів, що надходять, повинен бути виконаний акт аутентифікації.

Аутентифікація - це ресурсомісткий процес. Уявіть виконання SQL-запитів для кожного вхідного запиту проти вашого магазину користувачів, щоб перевірити відповідність uid / pwd. Або шифрувати та виконувати хеш-відповідність (стиль AWS). І архітектурно, кожен API REST повинен буде виконувати це, я думаю, використовуючи загальну послугу зворотного входу. Тому що, якщо ви цього не зробите, то ви скрізь засмічуєте авторський код. Великий безлад.

Так більше шарів, більше затримки.

Тепер перейдіть до Way-1 і подайте заявку на HTM. Чи дійсно ваш (людський) користувач хвилює, якщо вам доведеться надсилати uid / pwd / хеш чи що-небудь при кожному запиті? Ні, поки ви не заважаєте їй, кидаючи сторінку auth / login щосекунди. Удачі, якщо у вас є клієнти. Отже, що ви зробите, це зберігати інформацію для входу десь на стороні клієнта, у браузері, на самому початку, та надсилати її з кожним зробленим запитом. Для (людини) користувача вона вже увійшла, і "сеанс" доступний. Але насправді вона перевіряється автентичністю на кожен запит.

Те саме з Way-2. Ваш (людський) користувач ніколи не помітить. Тож ніякої шкоди не було зроблено.

Що робити, якщо ми застосуємо Way-1 до MTM? У цьому випадку, з моменту його роботи, ми можемо виправити цього хлопця, попросивши його подати інформацію про автентифікацію при кожному запиті. Всім все одно! Виконання шляху-2 на MTM не спричинить особливої ​​реакції; його чортова машина. Це могло б турбуватися менше!

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

Зрештою, філософії значення не мають. Що насправді важливо - це пошук інформації, презентація та досвід споживання. Якщо люди люблять ваші API, ви зробили свою роботу.


3
Сер, ви так красиво пояснили, що я маю чітке уявлення про основне питання / питання. Ти як Будда! Чи можу я додати, що, використовуючи HTTPS на транспортному шарі, ми можемо навіть запобігти атакам Man In the Middle, щоб ніхто не захопив мій ідентифікаційний ключ (якщо обраний шлях Way-1)
Vishnoo Rath,

Чи не завжди машина робить аутентифікацію? Людина не дає лайно щодо паролів, це прикро для роздратування користувачів, які правильно раціоналізують безпеку. Для мене проблема розробника, як вони хочуть, щоб машина працювала.
Тодд Баур

9
Я читаю вашу відповідь; у вашому рішенні для кожного окремого веб-запиту, що надходить на веб-переглядач, за допомогою клацань користувача, потрібно буде відправити "авторський маркер" назад у будь-який API, який викликає користувач. Що тоді? API здійснює перевірку маркера. Проти чого? Проти якогось "магазину жетонів", який підтверджує, чи маркер цей дійсний, чи ні. Чи не погоджуєтесь ви з тим, що той "магазин жетонів" потім стає хранителем "держави"? Дійсно, як би ви це не бачили, хтось десь повинен щось знати про "жетони", які передаються навколо діяльності користувачів. Там живе державна інформація.
Кінгз

5
Під службою "без громадянства" мається на увазі те, що конкретний серверний компонент (API CRUD) не містить жодного стану. Вони не розпізнають одного користувача від іншого і повністю заповнюють запит користувача за одну транзакцію. Це без громадянства. Але хтось десь повинен сидіти і приймати рішення про те, чи дійсний цей користувач, чи ні. Немає іншого способу зробити це; ключі або паролі чи що завгодно. Все, що передається з боку користувача, повинно бути підтверджено автентичністю та дозволом.
Кінгз

1
Вам не вистачає Way-3, гібридний підхід. Клієнт входить як в, Way-2але, як і в Way-1, облікові дані не перевіряються на будь-якому стані сервера. Незалежно від цього, авторський маркер створюється та надсилається назад клієнту як у Way-2. Пізніше цей маркер перевіряється на справжність, використовуючи асиметричну криптовалюту, шукаючи будь-яке стан клієнта.
jcoffland

50

Ось справді і повністю RESTful рішення аутентифікації:

  1. Створіть пара відкритих / приватних ключів на сервері аутентифікації.
  2. Розподіліть відкритий ключ на всіх серверах.
  3. Коли клієнт підтверджує автентифікацію:

    3.1. видайте маркер, який містить таке:

    • Термін придатності
    • ім'я користувача (необов’язково)
    • IP користувачів (необов’язково)
    • хеш пароля (необов’язково)

    3.2. Зашифруйте маркер приватним ключем.

    3.3. Відправити зашифрований маркер назад користувачеві.

  4. Коли користувач отримує доступ до будь-якого API, він також повинен перейти у свою токену аутентифікації.

  5. Сервери можуть перевірити, що маркер дійсний, розшифрувавши його за допомогою відкритого ключа сервера auth.

Це аутентифікація без стану / RESTful.

Зауважте, що якщо було включено хеш пароля, користувач також надсилатиме незашифрований пароль разом із маркером аутентифікації. Сервер міг переконатися, що пароль відповідає паролю, який використовувався для створення маркера аутентифікації, порівнюючи хеші. Необхідним буде безпечне з'єднання, що використовує щось на зразок HTTPS. Javascript на стороні клієнта може обробляти отримання пароля користувача та зберігання його на стороні клієнта, або в пам'яті, або в файлі cookie, можливо, зашифрованому відкритим ключем сервера .


5
Що робити, якщо хтось отримає цей авторський маркер і попросить API, прикидаючи його клієнтом?
Абіді

2
@Abidi, так, це проблема. Ви можете вимагати пароль. Хеш пароля може бути включений в маркер аутентифікації. Якщо комусь вдалося викрасти маркер, він би був уразливим для офлайн-грубих атак. Якби була обрана сильна парольна фраза, це не буде проблемою. Зауважте, що якщо ви використовували крадіжку токенів https, то зловмисник вимагатиме спочатку отримати доступ до клієнтської машини.
jcoffland

1
Тому що лише сервер автентифікації знає приватний ключ. Інші сервери можуть автентифікувати користувача, лише знаючи відкритий ключ та маркер користувача.
jcoffland

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

3
@jcoffland ви дійсно рекламували тут свою відповідь (неодноразово :-) Але я не можу не коментувати проблеми ефективності (інтенсивність обчислень) використання асиметричного шифрування під час кожного дзвінка. Я просто не бачу рішення, яке робить це, яке має будь-яку здатність до масштабування. Знайдіть HTTPS та протокол SPDY. Він триває, щоб тримати з'єднання відкритими (HTTP Keep-alives, який є державним), і обслуговувати декілька ресурсів у пакеті через одне і те ж з'єднання (більше стану), і звичайно сам SSL використовує лише асиметричне шифрування для обміну симетричним ключем шифру ( також держава).
Крейг

37

Якщо чесно з вами, я бачив тут чудові відповіді, але щось, що мене трохи турбує, - це коли хто докладе всю концепцію без громадянства до крайності, де це стане догматичним. Це нагадує мені тих старих шанувальників Smalltalk, які хотіли лише прийняти чистий ОО і якщо щось не є об'єктом, значить, ви робите це неправильно. Дай мені перерву.

Підхід RESTful повинен полегшити ваше життя та зменшити накладні витрати та витрати на заняття, спробуйте дотримуватися його, як це розумно робити, але хвилини, коли ви будете дотримуватися дисципліни (будь-якої дисципліни / настанови) до крайньої міри, де вона більше не забезпечує вигоду, для якої вона була призначена, ви робите це неправильно. Деякі з найкращих мов сьогодні мають функціональне програмування та орієнтацію на об'єкти.

Якщо найпростіший спосіб вирішити вашу проблему - зберігати ключ автентифікації у файлі cookie та надсилати його на заголовку HTTP, тоді робіть це, просто не зловживайте ним. Пам'ятайте, що сеанси погані, коли вони стають важкими та великими, якщо весь ваш сеанс складається з короткого рядка, що містить ключ, то в чому ж головна справа?

Я готовий прийняти виправлення в коментарях, але я просто не бачу сенсу (поки що) робити наше життя нещасним, щоб просто уникнути великого словника хешей на нашому сервері.


2
Люди не намагаються заборонити вам використовувати сеанси. Ви вільні це зробити. Але якщо ви це зробите, це НЕ ВІДБУДАТИ.
Андре Калдас

6
@ AndréCaldas, це не REST так само, як функціонування або примітивні типи в мові не є oop. Я не кажу, що проведення сеансів доцільно. Я просто висловлюю свою думку щодо того, як дотримуватись певної практики, до тієї міри, коли вони більше не дають комусь переваг. (До речі, зауважте, я не проти ваших зауважень, однак, я б не сказав, що це не REST, я б сказав, що це не чисто REST).
arg20

Отже, що ми називаємо це, якщо це НЕ ВІДПОВІДНО? І звичайно, якщо запит включає ідентифікатор сеансу, то це так само без громадянства, як запит, що включає ідентифікатор користувача? Чому користувач Id без громадянства та сеанс Id є статтю?
mfhholmes

1
Файли cookie вразливі до підроблення запитів між веб-сайтами, тому вони спрощують порушення безпеки. Краще використовувати те, що браузер не надсилається автоматично, як-от власний заголовок або спеціальна схема авторизації.
Dobes Vandermeer

1
Насправді, намагатися бути без громадянства - це не про догматизм, а про одну загальну концепцію SOA. Служби завжди мають користь від відключення та без громадянства: на практиці це полегшує масштабування, доступність та ремонтопридатність. Звичайно, це повинно бути якомога більше, і вам, зрештою, знадобляться якісь "оркестрові послуги", щоб керувати цими службами без громадянства в позитивний прагматичний підхід.
Арно Бушез

32

Перш за все, веб-сервіс RESTful - СТАТЕЛЕС (або іншими словами, SESSIONLESS). Тому служба RESTful не має і не повинна включати поняття сеансу чи файлів cookie. Спосіб аутентифікації або авторизації в службі RESTful - це використання заголовка авторизації HTTP, визначеного в специфікаціях HTTP RFC 2616. Кожен окремий запит повинен містити заголовок авторизації HTTP, а запит повинен бути надісланий через з'єднання HTTP (SSL). Це правильний спосіб аутентифікації та перевірки авторизації запитів у веб-сервісах HTTP RESTful. Я впровадив RESTful веб-сервіс для програми Cisco PRIME Performance Manager в Cisco Systems. І як частина цього веб-сервісу я також здійснив автентифікацію / авторизацію.


5
Ідентифікація HTTP все ще вимагає від сервера відстежувати ідентифікатори користувачів та паролі. Це не зовсім без громадянства.
jcoffland

21
Без громадянства в тому сенсі, що кожен запит є дійсним самостійно без будь-яких вимог попередніх запитів. Як це реалізовано на сервері - інша справа, якщо автентифікація дорога, ви можете виконати кешування та повторну автентифікацію пропуску кешу. Дуже мало серверів повністю без стану, де вихід є виключно функцією вводу. Зазвичай це запит або оновлення до певного стану.
Ерік Мартіно

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

1
@jcoffland Також ваше рішення значною мірою покладається на здатність сервера API розшифровувати підписаний маркер. Я вважаю, що цей підхід є не лише надто специфічним, але також є надто складним, щоб його можна було розглядати як підхід Р. Філдінг, маючи на увазі, щоб вирішити проблему RESTful аутентифікації.
Майкл Екока

2
@jcoffland Ви розумієте, наскільки сильно більш обчислювальним (а значить, ресурсомістким та глибоко повільним) є асиметричне шифрування? Ви говорите про схему, яка використовувала б асиметричне шифрування для кожного запиту. Найповільніший аспект HTTPS, без нічого, - це первинне рукостискання, яке передбачає створення публічних / приватних ключів для асиметричного шифрування загальної таємниці, яка згодом використовується для симетричного шифрування всього наслідкового зв'язку.
Крейг

22

Це, звичайно, не про "ключі сеансу", оскільки вони, як правило, використовуються для посилання на аутентифікацію без сеансу, яка виконується в межах усіх обмежень REST. Кожен запит є самоописом, містить достатньо інформації для авторизації запиту самостійно без будь-якого стану додатків на сервері.

Найпростіший спосіб підійти до цього - це почати із вбудованих механізмів аутентифікації HTTP в RFC 2617 .


Ідентифікація HTTP вимагає, щоб сервер зберігав ім'я користувача та пароль. Це стан сторони сервера і тому не суворо REST. Дивіться мою відповідь.
jcoffland

3
@jcoffland: Це просто неправда для обох облікових записів. Перший HTTP Auth не вимагає від сервера для зберігання пароля. Хеш пароля зберігається замість (Bcrypt з 8+ раундів рекомендується). По-друге, сервер не має жодного стану, оскільки заголовок авторизації надсилається з кожним запитом. І якщо ви вважаєте збережені хеші паролів державними , вони не більше стану, ніж збережені відкриті ключі.
Борис Б.

1
@Boris B., так, я розумію, що пароль зберігається як хеш. Хешований пароль все ще є специфічним для клієнта. Відмінність зберігання відкритого ключа, як описано в моєму рішенні, полягає в тому, що існує лише один відкритий ключ, відкритий ключ сервера аутентифікації. Це зовсім інакше, ніж зберігання хеша пароля на кожного користувача. Незалежно від того, як ви його одягаєте, якщо сервер зберігає пароль для кожного користувача, він зберігається відповідно до стану користувача і не становить 100% REST.
jcoffland

7
Я не думаю, що зберігання паролів хешеваних користувачів на сервері слід вважати станом на сервері. Користувачі - це ресурси, що містять інформацію, таку як ім’я, адреса чи хешований пароль.
Codepunkt

15

Стаття про "дуже проникливий", про яку згадує @skrebel ( http://www.berenddeboer.net/rest/authentication.html ), обговорюється складний, але дійсно порушений метод аутентифікації.

Ви можете спробувати відвідати сторінку (яка повинна переглядатись лише зареєстрованому користувачеві) http://www.berenddeboer.net/rest/site/authentication.html без будь-яких ідентифікаційних даних для входу.

(Вибачте, що не можу коментувати відповідь.)

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


Stripe.com сказав би інше, щоб ваш коментар щодо REST та Authentication не змішувався ..
Erik

Без громадянства посилається лише на сервер, а не на клієнта. Клієнт може запам'ятати весь стан сеансу та надіслати те, що стосується кожного запиту.
Dobes Vandermeer

Нарешті, хтось говорить про якийсь сенс, але автентифікація без громадянства можлива за допомогою криптовалюти з відкритим ключем. Дивіться мою відповідь.
jcoffland

1
На сервері немає "автентифікованого" стану. Він отримує інформацію через гіпермедіа і повинен співпрацювати з нею, щоб повернути те, що вимагали. Нічого менше, нічого більше. Якщо ресурс захищений і вимагає автентифікації та авторизації, надана гіпермедіа повинна включати цю інформацію. Я не знаю, звідки походить поняття про те, що автентифікація користувача перед поверненням ресурсу означає, що сервер відстежує стан. Надання імені користувача та пароля дуже просто може вважатися просто наданням більше параметрів фільтрації.
Майкл Екока

"Я б сказав, що REST та автентифікація просто не змішуються." Звучить як якийсь здоровий глузд. За винятком того, що система, несумісна з аутентифікацією (сама "автентифікована" - це, звичайно, стан), є обмеженою корисністю. Я відчуваю, що ми всі сперечаємось на перетині практичності та пуристського догматизму, і, відверто кажучи, практичність повинна перемогти. Є багато аспектів REST, які дуже корисні, не вникаючи в спори, намагаючись уникнути стану щодо аутентифікації, чи не так?
Крейг

12

Я думаю, що спокійна автентифікація передбачає передачу маркера аутентифікації як параметр у запиті. Прикладами є використання apikeys api's. Я не вірю, що використання файлів cookie чи http auth відповідає вимогам.


Файлів cookie та HTTP Auth слід уникати через вразливість CSRF.
Dobes Vandermeer

@DobesVandermeer Чи можете ви, будь ласка, побачити моє запитання, чи можете ви допомогти? stackoverflow.com/questions/60111743 / ...
Hemant Метален

12

Оновлення 16 лютого-2019

Раніше підхід, згаданий нижче, по суті є типом гранту " OAuth2.0" . Це простий спосіб встати і бігти. Однак при такому підході кожна програма в організації отримає власні механізми аутентифікації та авторизації. Рекомендований підхід - тип гранту "Код авторизації". Крім того, у своїй попередній відповіді нижче я рекомендував браузер localStorage для зберігання авторських жетонів. Однак я прийшов до думки, що печиво - це правильний варіант для цієї мети. У цій відповіді StackOverflow я детально пояснив свої причини, підхід до реалізації типу надання дозволу на отримання коду авторизації, міркування щодо безпеки тощо .


Я думаю, що для аутентифікації служби REST може бути використаний наступний підхід:

  1. Створіть API RESTful для входу, щоб прийняти ім'я користувача та пароль для автентифікації. Використовуйте метод HTTP POST для запобігання кешування та SSL для безпеки під час транзиту. Після успішної аутентифікації API повертає два JWT - один маркер доступу (коротша термін дії, скажімо, 30 хвилин) та один маркер оновлення (більша термін дії, скажімо, 24 години)
  2. Клієнт (веб-інтерфейс) зберігає JWT в локальній пам’яті та в кожному наступному виклику API передає маркер доступу у заголовку «Авторизація: носій #access token»
  3. API перевіряє дійсність маркера, перевіряючи дату підпису та термін дії. Якщо маркер дійсний, перевірте, чи користувач (він інтерпретує претензію "sub" в JWT як ім'я користувача) має доступ до API з допомогою пошуку кешу. Якщо користувач має право доступу до API, виконайте бізнес-логіку
  4. Якщо маркер минув, API повертає код відповіді HTTP 400
  5. Клієнт, отримуючи 400/401, викликає інший API REST з маркером оновлення у заголовку "Авторизація: Носій #refresh маркер", щоб отримати новий маркер доступу.
  6. Отримавши дзвінок із маркером оновлення, перевірте, чи маркер оновлення дійсний, перевіривши підпис та термін дії. Якщо маркер оновлення дійсний, оновіть кеш права доступу користувача з БД та поверніть новий маркер доступу та маркер оновлення. Якщо маркер оновлення недійсний, поверніть код відповіді HTTP 400
  7. Якщо новий маркер доступу та маркер оновлення повертаються, перейдіть до кроку 2. Якщо код відповіді HTTP 400 повернуто, клієнт припускає, що маркер оновлення закінчився, і запитає ім'я користувача та пароль у користувача
  8. Для виходу з системи очистіть місцевий сховище

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


тож би ви використали це для api зі статичним веб-сайтом, зробленим, наприклад, з кутовим? а що з мобільними додатками?
Язан Равашде

8

Ось так це зробити: Використання OAuth 2.0 для входу .

Ви можете використовувати інші методи аутентифікації, крім Google, якщо вони підтримують OAuth.


1
OAuth2 не захищений без HTTPS, ні без громадянства.
Арно Бушез

4
Нічого не захищено без HTTPS.
Крейг

1
@Craig І HTTPS також не може бути захищеним, якщо ланцюжок сертифікатів буде порушений, що може бути для більшого блага - en.wikipedia.org/wiki/Bullrun_(decryption_program) ;)
Арно Бушез

1
@ArnaudBouchez Будь ласка, уточніть, як мати розірваний ланцюжок сертифікатів на користь? Я не розумію, куди ти йдеш із цим. ;)
Крейг

@Craig Перейдіть за посиланням і насолоджуйтесь! Цей підхід до «більшого доброго» був явно цинічним у моєму коментарі: системи, подібні до бульбуна, призначені для «нашого блага» улюбленими та довірливими урядами.
Арно Бушез

3

Використання інфраструктури відкритого ключа, в якій реєстрація ключа передбачає належне прив'язування, гарантує, що відкритий ключ прив’язаний до особи, якій він присвоєний, таким чином, що забезпечує неприйняття

Дивіться http://en.wikipedia.org/wiki/Public_key_infrastructure . Якщо ви дотримуєтесь належних стандартів PKI, особу чи агента, який неправильно використовує викрадений ключ, можна виявити та заблокувати. Якщо агент вимагає використовувати сертифікат, прив'язка стає досить жорсткою. Розумний і швидкоплинний злодій може втекти, але вони залишають більше крихти.


2

Щоб відповісти на це питання з мого розуміння ...

Система аутентифікації, яка використовує REST, щоб вам не потрібно було фактично відслідковувати або керувати користувачами у вашій системі. Це робиться за допомогою методів HTTP POST, GET, PUT, DELETE. Ми приймаємо ці 4 методи і думаємо про них з точки зору взаємодії з базами даних як CREATE, READ, UPDATE, DELETE (але в Інтернеті ми використовуємо POST і GET, тому що саме зараз підтримують теги прив’язки). Тож трактуючи POST і GET як наш CREATE / READ / UPDATE / DELETE (CRUD), ми можемо розробити маршрути в нашому веб-додатку, які зможуть визначити, які дії CRUD ми досягаємо.

Наприклад, за допомогою програми Ruby on Rails ми можемо створити наш веб-додаток таким чином, що якщо користувач, який увійшов у систему, відвідує http://store.com/account/logout то GET цієї сторінки може розглядатися як користувач, що намагається вийти. . У нашому контролері рейок ми створили б дію, яка виводить користувача та відправляє їх на головну сторінку.

GET на сторінці входу дасть форму. POST на сторінці входу буде розглядатися як спроба входу, приймаючи дані POST і використовуючи їх для входу.

Для мене це практика використання методів HTTP, відображених у сенсі їх бази даних, а потім побудови системи аутентифікації, маючи на увазі, що вам не потрібно обходити будь-які ідентифікатори сеансу або відстежувати сеанси.

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


2

Поради щодо забезпечення будь-якої веб-програми

Якщо ви хочете захистити свою програму, тоді вам слід обов'язково почати використовувати HTTPS замість HTTP , це забезпечує створення захищеного каналу між вами та користувачами, що запобіжить нюхати дані, що надсилаються назад і назад користувачам, і допоможе зберегти дані обмінялися конфіденційно.

Ви можете використовувати JWTs (JSON Web Tokens) для захисту API RESTful , це має багато переваг у порівнянні з сеансами на сервері, переваги в основному:

1- Більш масштабована, оскільки ваші сервери API не повинні підтримувати сеанси для кожного користувача (що може бути великим тягарем, коли у вас багато сеансів)

2- JWT є автономними та мають претензії, які визначають роль користувача, наприклад, & що він може отримати та видав на дату та дату закінчення терміну дії (після чого JWT не буде дійсним)

3- Легше керувати через балансири завантаження і якщо у вас є кілька серверів API, оскільки вам не доведеться ділитися даними сеансу і не налаштовувати сервер для маршрутизації сеансу на один і той же сервер, коли запит із JWT потрапляє на будь-який сервер, його можна автентифікувати & уповноважений

4- Менший тиск на вашу БД, а також вам не доведеться постійно зберігати та отримувати ідентифікатори та дані сеансу для кожного запиту

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

Багато бібліотек надають прості способи створення та перевірки JWT в більшості мов програмування, наприклад: у node.js однією з найпопулярніших є jsonwebtoken

Оскільки API REST, як правило, спрямований на збереження сервера без стану, тому JWT більше сумісні з цією концепцією, оскільки кожен запит надсилається з токеном авторизації, який є автономним (JWT), без того, щоб сервер повинен відслідковувати сеанс користувача порівняно з сеансами, які роблять серверний стан, щоб він запам'ятовував користувача та його роль, проте сесії також широко використовуються та мають свої плюси, за якими ви можете шукати, якщо хочете.

Важливо відзначити, що вам потрібно надійно доставити JWT клієнту за допомогою HTTPS і зберегти його в безпечному місці (наприклад, на локальному сховищі).

Дізнатися більше про JWT можна за цим посиланням

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.