RESTful-аутентификация - PullRequest
       92

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

709 голосов
/ 26 ноября 2008

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

Ответы [ 14 ]

555 голосов
/ 23 августа 2011

Как обрабатывать аутентификацию в архитектуре 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 или Воспроизведение атак и специфичен для HTTP.

Сессия с помощью файлов cookie

Честно говоря, сеанс, управляемый на Сервере, не является действительно безгосударственным.

Одной из возможностей может быть сохранение всех данных в содержимом cookie. И, в соответствии с этим, cookie обрабатывается на стороне сервера (фактически клиент даже не пытается интерпретировать эти данные cookie: он просто передает их обратно на сервер при каждом последующем запросе). Но эти cookie-данные являются данными состояния приложения, поэтому ими должен управлять клиент, а не сервер, в чистом мире без сохранения состояния.

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

Сама техника cookie связана с HTTP, поэтому она не является действительно RESTful, которая должна быть независимой от протокола, ИМХО. Он уязвим для 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, который требуется в дополнение к любой схеме аутентификации.

412 голосов
/ 16 июля 2009

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

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

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

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

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

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

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

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

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

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

135 голосов
/ 24 ноября 2013

Достаточно уже сказано по этой теме хорошими людьми здесь. Но вот мои 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 способа:

Way-1:

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

Way-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. Ваш (человек) пользователь никогда не заметит. Так что никакого вреда не было.

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

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

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

51 голосов
/ 15 октября 2013

Вот подлинно и полностью RESTful решение для аутентификации:

  1. Создание пары открытый / закрытый ключ на сервере аутентификации.
  2. Распространение открытого ключа на все серверы.
  3. Когда клиент аутентифицируется:

    3.1. выдать токен, который содержит следующее:

    • Время истечения
    • имя пользователя (необязательно)
    • IP пользователей (опционально)
    • хеш пароля (необязательно)

    3,2. Зашифруйте токен с помощью закрытого ключа.

    3,3. Отправьте зашифрованный токен обратно пользователю.

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

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

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

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

36 голосов
/ 14 августа 2013

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

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

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

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

32 голосов
/ 27 марта 2013

Прежде всего, веб-сервис RESTful имеет вид STATELESS (или, другими словами, SESSIONLESS ). Следовательно, сервис RESTful не имеет и не должен иметь понятия сеанса или файлов cookie. Способ выполнения аутентификации или авторизации в службе RESTful заключается в использовании заголовка авторизации HTTP, как определено в спецификациях HTTP RFC 2616. Каждый отдельный запрос должен содержать заголовок авторизации HTTP, а запрос должен отправляться через соединение HTTP (SSL). Это правильный способ проверки подлинности и проверки авторизации запросов в веб-службах HTTP RESTful. Я реализовал веб-сервис RESTful для приложения Cisco PRIME Performance Manager в Cisco Systems. И как часть этой веб-службы я также ввел аутентификацию / авторизацию.

Рубенс Гомес.

22 голосов
/ 26 ноября 2008

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

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

15 голосов
/ 15 октября 2012

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

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

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

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

12 голосов
/ 14 января 2017

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

Подход, упомянутый ранее ниже, по существу, является типом предоставления "Credential Password Owner Resource" 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 с токеном обновления в заголовке «Authorization: Bearer #refresh token», чтобы получить новый токен доступа.
  6. При получении вызова с токеном обновления проверьте, действителен ли токен обновления, проверив подпись и дату истечения срока действия. Если токен обновления действителен, обновите кэш прав доступа пользователя из БД и верните новый токен доступа и токен обновления. Если токен обновления недействителен, верните код ответа HTTP 400
  7. Если возвращены новый токен доступа и токен обновления, перейдите к шагу 2. Если возвращается код ответа HTTP 400, клиент предполагает, что срок действия маркера обновления истек, и запрашивает у пользователя имя пользователя и пароль
  8. Для выхода из системы очистить локальное хранилище

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

12 голосов
/ 19 января 2009

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

...