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

746

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

Джим Кинер
источник
3
Когда я гугляю Restful Authentication, я нахожу дюжину плагинов RoR. Я предполагаю, что это не то, что вы ищете. Если не RoR, то на каком языке? Какой веб-сервер?
S.Lott
2
Это не будет ужасно неправильно, если вы используете HTTPS. Полный HTTP-запрос вместе с URL будет зашифрован.
Бхарат Хатри
4
@BharatKhatri: Да, это будет. Я никогда не передам конфиденциальную информацию в URL, видимом для пользователя. Эта информация гораздо более вероятна для практических целей. HTTPS не может помочь для случайной утечки.
Джо Со
2
@jcoffland: Что вы подразумеваете под реальной аутентификацией RESTful? Я заинтересован, потому что я только что реализовал третий способ из принятого ответа, однако я не доволен им (мне не нравится дополнительный параметр в URL).
BlueLettuce16
4
некоторые люди используют jwt.io/introduction, чтобы решить эту проблему .. Я сейчас исследую это, чтобы решить мое дело: stackoverflow.com/questions/36974163/… >> Надеюсь, это будет работать нормально.
Тоха

Ответы:

586

Как обрабатывать аутентификацию в RESTful клиент-серверной архитектуре - вопрос спорный.

Обычно это может быть достигнуто в мире SOA через HTTP с помощью:

  • HTTP базовая аутентификация через HTTPS;
  • Cookies и управление сессиями;
  • Токен в заголовках 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 .

Предоставляется через токен (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's Encrypt нет никаких причин не использовать надлежащий HTTPS, который требуется в дополнение к любой схеме аутентификации.

Арно Буше
источник
5
Если вы используете его Cookieкак лучшую замену, HTTP Basic Authвы можете выполнить аутентификацию без сохранения состояния с методом истечения срока аутентификации и возможностью выхода из системы. Пример реализации может использовать cookie, вызываемый Emulated-HTTP-Basic-Authсо значением, аналогичным реальному HTTP Basic Auth, и дополнительно установленным сроком действия. Выход может быть осуществлен с удалением этого куки. Я предполагаю, что любой клиент, способный поддерживать 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 Forbidden. Страница ошибок может содержать метод входа или ссылку на него. Однако самый большой аргумент против файлов cookie и проверки подлинности http (независимо от того, находится ли состояние на стороне сервера или на стороне клиента), заключается в том, что они уязвимы для подделки межсайтовых запросов. По этой причине лучшим подходом является пользовательская схема авторизации, пользовательский заголовок авторизации или пользовательский параметр GET или POST.
Добес Вандермер
418

Я сомневаюсь, пытались ли когда-нибудь люди, которые с энтузиазмом выкрикивали «HTTP-аутентификацию», создавать приложение на основе браузера (вместо веб-службы «машина-машина») с REST (без обид, - я просто не думаю, что они когда-либо сталкивались с трудностями) ,

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

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

Очень проницательная статья, в которой рассматриваются эти вопросы по пунктам, находится здесь , но это приводит к множеству специфических для браузера хакеров javascript, обходных путей для обходных путей и так далее. Как таковой, он также не является совместимым с форвардом, поэтому потребует постоянного обслуживания по мере выпуска новых браузеров. Я не считаю этот чистый и понятный дизайн, плюс я чувствую, что это большая дополнительная работа и головная боль, просто чтобы я с энтузиазмом мог показать свой REST-значок моим друзьям.

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

Делая сессии RESTful-ресурсом только со следующими правилами:

  • Сессия отображает ключ к идентификатору пользователя (и , возможно, в последнюю экшен-метку времени для тайм - аута)
  • Если сеанс существует, то это означает, что ключ действителен.
  • Вход в систему означает POSTing для / сессий, новый ключ устанавливается как cookie
  • Выход из системы означает УДАЛЕНИЕ / сессий / {ключ} (помните, что при перегруженном POST мы браузер, а HTML 5 еще долгий путь)
  • Аутентификация выполняется путем отправки ключа в виде куки-файла при каждом запросе и проверки, существует ли сеанс и является ли он действительным

Теперь единственное отличие от HTTP-аутентификации состоит в том, что ключ аутентификации генерируется сервером и отправляется клиенту, который продолжает отправлять его обратно, а не клиенту, который вычисляет его по введенным учетным данным.

Конвертер42 добавляет, что при использовании https (что нам и следует) важно, чтобы в файле cookie был установлен флаг безопасности, чтобы информация аутентификации никогда не отправлялась по незащищенному соединению. Отличный момент, сам не видел.

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

skrebbel
источник
68
Это прагматичный ответ, и предлагаемое решение работает. Однако использование терминов «RESTful» и «сеанс» в одном и том же предложении просто неверно (если только между ними нет «not»;). Другими словами: любой веб-сервис, который использует сеансы, НЕ является RESTful (по определению). Не поймите меня неправильно - вы все еще можете использовать это решение (YMMV), но термин «RESTful» не может быть использован для него. Я рекомендую книгу О'Рейли о ОТДЫХЕ, которая очень читабельна и подробно объясняет предмет.
Джондо
23
@skrebbel: чистое решение REST будет отправлять данные аутентификации каждый раз, когда запрашивает ресурс, что не идеально (HTTP Auth делает это). Предлагаемое решение работает и лучше для большинства случаев использования, но не является RESTful. Нет необходимости в войне, я тоже использую это решение. Я просто не утверждаю, что это ОТДЫХ. :)
johndodo
94
Ну давай, дай пример тогда. Что это за другой способ, который работает хорошо? Я искренне хотел бы знать. HTTP Auth, конечно, нет, вы не можете выйти из системы, не закрыв браузер, и вы не можете предложить приличный UX для входа в систему без большого количества JS, не совместимых с браузером. Меня не волнует "чисто RESTful" против "почти RESTful" и связанных с ними религиозных дебатов, но если вы скажете, что есть несколько способов, вы должны изложить их.
скреббель
15
Настоящая аутентификация RESTful с пользовательскими агентами реального мира (так называемыми «браузерами») состоит из файла cookie, содержащего значение HTTP-аутентификации. Таким образом, сервер может предоставить пользовательский интерфейс для ввода логина и пароля, а сервер может принудительно выйти из системы (удалив cookie). Кроме того, вместо ответа 401 на требование входа в систему при сбое аутентификации сервер должен использовать временное перенаправление на экран входа в систему, а после успешного входа в систему использовать временное перенаправление назад в предыдущее местоположение. Кроме того, сервер должен встроить действие выхода из системы (форма POST) практически на каждую страницу для зарегистрированных пользователей.
Микко Ранталайнен
15
Я не вижу ничего плохого в использовании «restful» и «session» в одном предложении, если ясно, что сессия существует только на стороне клиента. Я не уверен, почему такая большая сделка об этой концепции.
Джо Филлипс
140

Достаточно уже сказано на эту тему хорошими людьми здесь. Но вот мои 2 цента.

Есть 2 режима взаимодействия:

  1. человек-машина (HTM)
  2. машина к машине (MTM)

Машина является общим знаменателем, выраженным как API REST, а субъектами / клиентами являются люди или машины.

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

Когда мы рассматриваем это в контексте приложений «человек-машина», «основанных на браузере», как указывает Скреббель выше, это означает, что (веб) -приложение, работающее в браузере, должно будет отправлять свое состояние и соответствующую информацию с каждым запросом это делает к концу API REST.

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

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

Концепция аутентификации применяется по всем направлениям. Как вы будете проектировать это так, чтобы к вашим API-интерфейсам REST обращались единообразно и безопасно? Как я вижу это, есть 2 способа:

Путь-1:

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

Путь-2:

  1. Клиент начинается с запроса авторизации
  2. API REST входа в систему будет обрабатывать все такие запросы
  3. Он принимает параметры аутентификации (ключ API, uid / pwd или все, что вы выберете) и проверяет аутентификацию по хранилищу пользователей (LDAP, AD или MySQL DB и т. Д.)
  4. Если проверено, создает токен аутентификации и передает его клиенту / вызывающей стороне
  5. Затем вызывающий абонент отправляет этот маркер авторизации + конкретные параметры запроса с каждым последующим запросом другим бизнес-API REST до выхода из системы или до истечения срока аренды

Очевидно, что в способе 2 API REST потребуется способ распознавать и доверять токену как действительному. API входа выполнил проверку подлинности, и поэтому этот «ключ камердинера» должен доверять другим API REST в вашем каталоге.

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

Но я отвлекся.

Дело в том, что «состояние» (о состоянии аутентификации клиента) необходимо поддерживать и совместно использовать, чтобы все API REST могли создать круг доверия. Если мы этого не делаем, что является способом-1, мы должны принять, что акт аутентификации должен быть выполнен для любых / всех поступающих запросов.

Выполнение аутентификации является ресурсоемким процессом. Представьте себе выполнение запросов SQL для каждого входящего запроса к вашему хранилищу пользователей для проверки соответствия uid / pwd. Или для шифрования и выполнения хеш-совпадений (стиль AWS). И архитектурно, каждый API REST должен будет выполнять это, я подозреваю, используя общую внутреннюю службу входа в систему. Потому что, если вы этого не сделаете, то вы засоряете код авторизации везде. Большой беспорядок

Чем больше слоев, тем больше задержка.

Теперь возьми Way-1 и подай заявку на HTM. Ваш (человеческий) пользователь действительно заботится, нужно ли вам отправлять uid / pwd / hash или что-то еще с каждым запросом? Нет, если вы не беспокоите ее, бросая страницу авторизации / входа в систему каждую секунду. Удачи, если у вас есть клиенты. Итак, что вы будете делать, это хранить информацию для входа в систему где-нибудь на стороне клиента, в браузере, в самом начале и отправлять ее при каждом запросе. Для пользователя (пользователя) она уже вошла в систему, и доступна «сессия». Но на самом деле она проходит проверку подлинности при каждом запросе.

То же самое с путем-2. Ваш (человек) пользователь никогда не заметит. Так что никакого вреда не было.

Что, если мы применим Путь 1 к МТМ? В этом случае, поскольку это машина, мы можем чертовски устать от этого парня, попросив его отправлять аутентификационную информацию при каждом запросе. Никому нет дела! Выполнение Way-2 на MTM не вызовет особой реакции; это чертова машина. Это может заботиться меньше!

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

В конце концов, философии не имеют значения. Что действительно важно, так это раскрытие информации, презентация и опыт потребления. Если люди любят ваши API, вы сделали свою работу.

Kingz
источник
3
Сэр, вы объяснили это так прекрасно, что у меня есть четкое представление об основной проблеме / вопросе под рукой. Ты как Будда! Могу добавить, что, используя HTTPS на транспортном уровне, мы можем даже предотвратить атаки Man In the Middle, чтобы никто не угонял мой ключ идентификатора (если выбран путь 1)
Vishnoo Rath
Разве это не всегда машина, выполняющая аутентификацию? Человек не заботится о паролях, это досадное раздражение для пользователей, которые правильно обосновывают безопасность. Для меня проблема разработчика в том, как они хотят, чтобы машина выполняла свою работу.
Тодд Баур
9
Я читаю ваш ответ; В вашем решении для каждого отдельного веб-запроса, генерируемого в браузере пользовательскими кликами, необходимо отправлять «токен аутентификации» обратно в любой API, вызываемый щелчком пользователя. Что тогда? API выполняет проверку токена. Против чего? Против какого-то «хранилища токенов», которое подтверждает, действителен ли этот токен или нет. Разве вы не согласны с тем, что этот «магазин токенов» становится хранителем «государства»? Действительно, как бы вы это ни видели, кто-то где-то должен знать что-то о «токенах», распространяемых по действиям пользователя. Вот где живет государственная информация.
Kingz
5
А под услугой без сохранения состояния на самом деле подразумевается то, что этот конкретный компонент сервера (API-интерфейсы CRUD) не несет никаких состояний. Они не распознают одного пользователя от другого и полностью выполняют запрос пользователя за одну транзакцию. Это безгражданство. Но кто-то где-то должен сидеть и выносить суждение о том, является ли этот пользователь действительным или нет. Нет другого способа сделать это; ключи или пароли или что угодно. Все, что передается со стороны пользователя, должно быть аутентифицировано и авторизовано.
Kingz
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. Серверы могут проверить, что токен действителен, расшифровав его с помощью открытого ключа сервера аутентификации.

Это аутентификация без сохранения состояния / RESTful.

Обратите внимание, что при включении хэша пароля пользователь также отправит незашифрованный пароль вместе с токеном аутентификации. Сервер может проверить, совпадает ли пароль с паролем, использованным для создания токена аутентификации, путем сравнения хешей. Безопасное соединение, использующее что-то вроде HTTPS, будет необходимо. Javascript на стороне клиента может обрабатывать получение пароля пользователя и сохранение его на стороне клиента, либо в памяти, либо в cookie-файле, возможно, зашифрованном с помощью открытого ключа сервера .

jcoffland
источник
5
Что если кто-то завладеет этим токеном авторизации и вызовет API, притворяясь клиентом?
Абиди
2
@ Абиди, да, это проблема. Вы могли бы потребовать пароль. Хеш пароля может быть включен в маркер аутентификации. Если кто-то сможет украсть токен, он будет уязвим для атак с использованием грубой силы. Если бы была выбрана надежная фраза-пароль, это не было бы проблемой. Обратите внимание, что если вы использовали кражу токена https, злоумышленник сначала должен получить доступ к компьютеру клиента.
jcoffland
1
Потому что только сервер аутентификации знает закрытый ключ. Другие серверы могут аутентифицировать пользователя, зная только открытый ключ и токен пользователя.
jcoffland
1
Асимметричное шифрование и дешифрование на порядок медленнее (более ресурсоемкое), чем симметричное шифрование. Если сервер использует открытый ключ для расшифровки токена при каждом вызове, это станет огромным препятствием для производительности.
Крейг
3
@jcoffland Вы действительно продвигали свой ответ здесь (неоднократно :-) Но я не могу не комментировать проблемы производительности (интенсивность вычислений) использования асимметричного шифрования при каждом вызове. Я просто не могу найти решение, которое делает это, имея возможность масштабировать. Посмотрите HTTPS и протокол SPDY. Он идет на все, чтобы поддерживать открытые соединения (HTTP keep-alives, который является состоянием), и обслуживать несколько ресурсов в пакетном режиме по одному и тому же соединению (больше состояния), и, конечно, сам SSL использует только асимметричное шифрование для обмена симметричным ключом шифрования ( также государство).
Крейг
37

Если честно, я видел здесь отличные ответы, но меня немного беспокоит то, что кто-то доведет всю концепцию безгражданства до крайности, когда она станет догматичной. Это напоминает мне о тех старых фанатах Smalltalk, которые хотели только принять чистый ОО, и если что-то не является объектом, то вы делаете это неправильно. Дай мне перерыв.

Предполагается, что подход RESTful сделает вашу жизнь проще и сократит накладные расходы и затраты на сеансы, постарайтесь следовать им, как это целесообразно, но в ту минуту, когда вы следуете дисциплине (любой дисциплине / руководству) до крайности, когда больше не дает выгоды, для которой он был предназначен, тогда вы делаете это неправильно. Некоторые из лучших современных языков имеют функциональное программирование и объектную ориентацию.

Если самый простой способ решить вашу проблему - это сохранить ключ аутентификации в файле cookie и отправить его в заголовке HTTP, тогда сделайте это, только не злоупотребляйте им. Помните, что сессии плохие, когда они становятся тяжелыми и большими, если весь ваш сеанс состоит из короткой строки, содержащей ключ, то в чем же дело?

Я открыт для принятия исправлений в комментариях, но я просто не вижу смысла (пока) в том, чтобы сделать нашу жизнь несчастной, чтобы просто не хранить большой словарь хэшей на нашем сервере.

arg20
источник
2
Люди не пытаются запретить вам использовать сессии. Вы можете сделать это Но если вы это сделаете, это не ОТДЫХ.
Андре Калдас
6
@ AndréCaldas это не REST таким же образом, что наличие функций или примитивных типов в языке не является опа. Я не говорю, что желательно проводить сессии. Я просто высказываю свое мнение о том, чтобы следовать ряду практик до такой степени, чтобы они больше не давали кому-то преимущества. (Кстати, обратите внимание, я не возражал против ваших замечаний, однако я бы не сказал, что это не ОТДЫХ, я бы сказал, что это не просто ОТДЫХ).
arg20
Итак, как мы это называем, если это не RESTful? И, конечно же, если запрос включает идентификатор сеанса, то это так же без сохранения состояния, как запрос, включающий идентификатор пользователя? Почему пользовательский идентификатор не имеет состояния, а идентификатор сеанса - состояние?
mfhholmes
1
Куки-файлы уязвимы для подделки межсайтовых запросов, поэтому они облегчают нарушения безопасности. Лучше использовать что-то, что не отправляется браузером автоматически, например пользовательский заголовок или схему авторизации.
Добес Вандермер
1
На самом деле, попытка остаться без гражданства - это не догматизм, а одна общая концепция самой SOA. Службы всегда должны получать выгоду от разобщенности и отсутствия состояния: на практике это облегчает масштабирование, доступность и ремонтопригодность. Конечно, это должно быть как можно больше, и в конечном итоге вам понадобятся некоторые «сервисы оркестровки», чтобы управлять этими сервисами без учета состояния с прагматическим подходом с сохранением состояния.
Арно Бушез
32

Прежде всего, веб-сервис RESTful является STATELESS (или, другими словами, 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-аутентификация не требует от сервера хранить пароль. Хэш пароля хранится вместо (Bcrypt с 8+ раундов рекомендуется). Во-вторых, у сервера нет состояния, поскольку заголовок авторизации отправляется с каждым запросом. И если вы рассматриваете сохраненные хэши паролей как состояние , они являются не более состоянием, чем хранимые открытые ключи.
Борис Б.
1
@ Борис Б., да, я понимаю, что пароль хранится в виде хэша. Хешированный пароль все еще зависит от клиента. Разница с хранением открытого ключа, как описано в моем решении, заключается в том, что существует только один открытый ключ, открытый ключ сервера аутентификации. Это очень отличается от хранения хэша пароля для пользователя. Независимо от того, как вы одеваетесь, если сервер хранит пароль для каждого пользователя, он сохраняется для каждого пользовательского состояния и не является 100% REST.
jcoffland
7
Я не думаю, что хранение хеш-пароля пользователя на сервере должно рассматриваться как состояние на стороне сервера. Пользователи - это ресурсы, содержащие информацию, такую ​​как имя, адрес или хешированный пароль.
Codepunkt
15

В «очень проницательной» статье, упомянутой @skrebel ( http://www.berenddeboer.net/rest/authentication.html ), обсуждается запутанный, но действительно неработающий метод аутентификации.

Вы можете попытаться посетить страницу (которая должна быть доступна для просмотра только авторизованному пользователю) http://www.berenddeboer.net/rest/site/authenticated.html без каких-либо учетных данных для входа.

(Извините, я не могу прокомментировать ответ.)

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

Джи Хан
источник
Stripe.com сказал бы иначе ваш комментарий о том, что REST и аутентификация не смешиваются ..
Эрик,
Состояние без сохранения относится только к серверу, а не к клиенту. Клиент может запомнить все состояние сеанса и отправить то, что имеет отношение к каждому запросу.
Добес Вандермер
Наконец, кто-то говорит о каком-то смысле, но аутентификация без сохранения состояния возможна с использованием криптографии с открытым ключом. Смотри мой ответ.
jcoffland
1
Сервер не имеет "аутентифицированного" состояния. Он получает информацию через гипермедиа и должен работать с ней, чтобы вернуть то, что было запрошено. Ни меньше, ни больше. Если ресурс защищен и требует аутентификации и авторизации, предоставленная гипермедиа должна включать эту информацию. Я не знаю, откуда взялась идея, что аутентификация пользователя перед возвратом ресурса означает, что сервер отслеживает состояние. Предоставление имени пользователя и пароля вполне может рассматриваться как простое предоставление большего количества параметров фильтрации.
Майкл Экока
«Я бы сказал, REST и аутентификация просто не смешиваются». Походит на некоторый здравый смысл. За исключением того, что система, которая несовместима с аутентификацией (сама «аутентифицированная», конечно, является состоянием), имеет ограниченную полезность. Я чувствую, что мы все спорим о пересечении практичности и пуристского догматизма, и откровенно практичность должна победить. Есть много аспектов REST, которые очень полезны, не вдаваясь в искажения, пытаясь избежать состояния в отношении аутентификации, не так ли?
Крейг
12

Я думаю, что спокойная аутентификация включает передачу токена аутентификации в качестве параметра в запросе. Примерами являются использование apikeys от api. Я не верю, что использование cookie-файлов или http-аутентификации оправдано.

Bjorn
источник
Куки и HTTP-аутентификации следует избегать из-за уязвимости CSRF.
Добес Вандермер
@DobesVandermeer Можете ли вы увидеть мой вопрос, если вы можете помочь? stackoverflow.com/questions/60111743/…
Хемант Металия
12

Обновление от 16 февраля 2019 г.

Подход, упомянутый ранее ниже, по существу является типом предоставления OAuth2.0 « Учетная запись пароля владельца ресурса» . Это простой способ начать работу. Однако при таком подходе каждое приложение в организации будет иметь собственные механизмы аутентификации и авторизации. Рекомендуемый подход - тип предоставления «Код авторизации». Кроме того, в моем предыдущем ответе ниже я рекомендовал браузер localStorage для хранения токенов авторизации. Тем не менее, я пришел к выводу, что cookie является правильным вариантом для этой цели. В этом ответе StackOverflow я подробно изложил свои причины, подход к реализации типа предоставления кода авторизации, соображения безопасности и т . Д.


Я думаю, что следующий подход может быть использован для аутентификации службы REST:

  1. Создайте API RESTful для входа в систему, чтобы принять имя пользователя и пароль для аутентификации. Используйте метод HTTP POST для предотвращения кэширования и SSL для обеспечения безопасности во время транзита. При успешной аутентификации API возвращает два JWT - один токен доступа (более короткий срок действия, скажем, 30 минут) и один токен обновления (более длинный срок действия, скажем, 24 часа).
  2. Клиент (веб-интерфейс) сохраняет JWT в локальном хранилище и при каждом последующем вызове API передает маркер доступа в заголовке «Authorization: Bearer #access token»
  3. API проверяет действительность токена, проверяя подпись и дату истечения срока действия. Если токен действителен, проверьте, имеет ли пользователь (он интерпретирует утверждение «sub» в JWT как имя пользователя) доступ к API с поиском в кэше. Если пользователь авторизован для доступа к API, выполните бизнес-логику
  4. Если срок действия токена истек, API возвращает код ответа HTTP 400
  5. При получении 400/401 клиент вызывает другой API REST с токеном обновления в заголовке «Авторизация: Bearer #refresh token», чтобы получить новый токен доступа.
  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 Пожалуйста, перейдите по ссылке, и наслаждайтесь! Этот подход «большего блага» был явно циничным в моем комментарии: подобные Bullrun системы предназначены для «нашего блага» нашими любимыми и доверчивыми правительствами.
Арно Бушез
3

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

См. Http://en.wikipedia.org/wiki/Public_key_infrastructure . Если вы соблюдаете надлежащие стандарты PKI, лицо или агент, который неправильно использует украденный ключ, может быть идентифицирован и заблокирован. Если агенту требуется использовать сертификат, привязка становится довольно жесткой. Умный и быстроходный вор может убежать, но они оставляют больше крошек.

DonB.
источник
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 этой страницы можно было увидеть как пользователь, пытающийся выйти из системы. , В нашем контроллере rails мы создали бы действие, которое выводит пользователя из системы и отправляет его обратно на домашнюю страницу.

GET на странице входа даст форму. POST на странице входа в систему будет рассматриваться как попытка входа в систему, при этом данные POST будут использоваться для входа в систему.

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

Я все еще учусь - если вы обнаружите, что я сказал что-то неправильно, поправьте меня, и если вы узнаете больше, опубликуйте это здесь. Спасибо.


источник
2

Советы действительны для защиты любого веб-приложения

Если вы хотите защитить свое приложение, то вам определенно следует начать с использования HTTPS вместо HTTP , это обеспечит создание безопасного канала между вами и пользователями, что предотвратит перехват данных, отправляемых пользователям назад и вперед, и поможет сохранить данные обменялись конфиденциально.

Вы можете использовать JWT (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 по этой ссылке

Ахмед Элкусси
источник