Я разрабатываю REST API, требующий аутентификации. Поскольку сама аутентификация происходит через внешний веб-сервис по HTTP, я решил, что мы будем выдавать токены, чтобы избежать повторного вызова службы аутентификации. Это подводит меня к моему первому вопросу:
Действительно ли это лучше, чем просто требовать от клиентов использовать HTTP Basic Auth для каждого запроса и кешировать вызовы на стороне сервера службы аутентификации?
Преимущество решения Basic Auth заключается в том, что не требуется полного цикла к серверу, прежде чем могут начаться запросы контента. Токены потенциально могут быть более гибкими по объему (т.е. предоставлять права только на определенные ресурсы или действия), но это кажется более подходящим для контекста OAuth, чем мой более простой вариант использования.
В настоящее время токены приобретаются так:
curl -X POST localhost/token --data "api_key=81169d80...
&verifier=2f5ae51a...
×tamp=1234567
&user=foo
&pass=bar"
api_key
, timestamp
И verifier
требуется все запросы. "Подтверждающий" возвращается:
sha1(timestamp + api_key + shared_secret)
Я намерен разрешить вызовы только от известных абонентов и предотвратить дословное повторное использование вызовов.
Это достаточно хорошо? Underkill? Overkill?
С токеном на руках клиенты могут приобретать ресурсы:
curl localhost/posts?api_key=81169d80...
&verifier=81169d80...
&token=9fUyas64...
×tamp=1234567
Для самого простого возможного звонка это кажется ужасно многословным. Учитывая, что в shared_secret
конечном итоге это будет встроено (как минимум) в приложение iOS, из которого, я полагаю, оно может быть извлечено, предлагает ли это вообще что-либо, кроме ложного чувства безопасности?
источник
Ответы:
Позвольте мне все разделить и решить каждую проблему изолированно:
Аутентификация
Для аутентификации baseauth имеет то преимущество, что это зрелое решение на уровне протокола. Это означает, что многие проблемы, которые «могут возникнуть позже» , уже решены для вас. Например, с помощью BaseAuth пользовательские агенты знают, что пароль является паролем, поэтому они не кэшируют его.
Загрузка сервера аутентификации
Если вы выдаете токен пользователю вместо кеширования аутентификации на своем сервере, вы по-прежнему делаете то же самое: кэшируете информацию аутентификации. Единственная разница в том, что вы перекладываете ответственность за кеширование на пользователя. Это кажется ненужным трудом для пользователя без каких-либо выгод, поэтому я рекомендую сделать это прозрачно на вашем сервере, как вы предложили.
Безопасность передачи
Если вы можете использовать SSL-соединение, это все, что вам нужно, это безопасное соединение *. Чтобы предотвратить случайное многократное выполнение, вы можете отфильтровать несколько URL-адресов или попросить пользователей включить в URL-адрес случайный компонент ("nonce").
Если это невозможно и передаваемая информация не является секретной, я рекомендую защитить запрос хешем, как вы предложили в подходе с использованием токена. Поскольку хэш обеспечивает безопасность, вы можете указать своим пользователям предоставить хеш в качестве пароля baseauth. Для повышения надежности я рекомендую использовать случайную строку вместо временной метки в качестве «одноразового номера», чтобы предотвратить атаки повторного воспроизведения (два законных запроса могут быть сделаны в течение одной секунды). Вместо того, чтобы предоставлять отдельные поля «общий секрет» и «ключ api», вы можете просто использовать ключ api в качестве общего секрета, а затем использовать соль, которая не изменяется, чтобы предотвратить атаки радужной таблицы. Поле имени пользователя кажется хорошим местом для размещения одноразового номера, так как это часть auth. Итак, теперь у вас есть такой чистый вызов:
Правда, это немного утомительно. Это потому, что вы не используете решение на уровне протокола (например, SSL). Так что было бы неплохо предоставить пользователям какой-то SDK, чтобы, по крайней мере, им не приходилось проходить его самостоятельно. Если вам нужно сделать это таким образом, я считаю соответствующий уровень безопасности (just-right-kill).
Безопасное секретное хранилище
Это зависит от того, кому вы пытаетесь помешать. Если вы запрещаете людям, имеющим доступ к телефону пользователя, использовать вашу службу REST от имени пользователя, то было бы неплохо найти какой-то API-интерфейс связки ключей в целевой ОС и сохранить в SDK (или разработчике) ключ там. Если это невозможно, вы можете хотя бы немного усложнить получение секрета, зашифровав его и сохранив зашифрованные данные и ключ шифрования в отдельных местах.
Если вы пытаетесь помешать другим поставщикам программного обеспечения получить ваш ключ API, чтобы предотвратить разработку альтернативных клиентов, почти работает только подход шифрования и хранения отдельно . Это криптография белого ящика, и на сегодняшний день никто не придумал действительно безопасного решения проблем этого класса. Самое меньшее, что вы можете сделать, - это по-прежнему выдавать один ключ для каждого пользователя, чтобы вы могли заблокировать злоупотребленные ключи.
(*) РЕДАКТИРОВАТЬ: SSL-соединения больше не должны считаться безопасными без дополнительных шагов для их проверки .
источник
Чистый RESTful API должен использовать стандартные функции базового протокола:
Для HTTP RESTful API должен соответствовать существующим стандартным заголовкам HTTP. Добавление нового заголовка HTTP нарушает принципы REST. Не изобретайте колесо заново, используйте все стандартные функции в стандартах HTTP / 1.1, включая коды ответов о состоянии, заголовки и так далее. Веб-службы RESTFul должны использовать стандарты HTTP и полагаться на них.
Сервисы RESTful ДОЛЖНЫ БЫТЬ БЕЗГРАЖДАННЫМИ Любые уловки, такие как аутентификация на основе токенов, которая пытается запомнить состояние предыдущих запросов REST на сервере, нарушают принципы REST. Опять же, это ОБЯЗАТЕЛЬНО; то есть, если ваш веб-сервер сохраняет любую информацию, относящуюся к контексту запроса / ответа, на сервере, пытаясь установить какой-либо сеанс на сервере, тогда ваш веб-сервис НЕ является Stateless. И если это НЕ без гражданства, это НЕ RESTFul.
Итог: для целей аутентификации / авторизации следует использовать стандартный заголовок авторизации HTTP. То есть вы должны добавлять заголовок HTTP-авторизации / аутентификации в каждый последующий запрос, который необходимо аутентифицировать. REST API должен соответствовать стандартам схемы HTTP-аутентификации. Особенности форматирования этого заголовка определены в стандартах RFC 2616 HTTP 1.1 - раздел 14.8 Авторизация RFC 2616 и в RFC 2617 HTTP-аутентификация: базовая и дайджест-аутентификация доступа. ,
Я разработал службу RESTful для приложения Cisco Prime Performance Manager. Найдите в Google документ REST API, который я написал для этого приложения, чтобы получить более подробную информацию о соответствии RESTFul API здесь . В этой реализации я решил использовать схему авторизации HTTP «Basic». - проверьте версию 1.5 или выше этого документа REST API и выполните поиск авторизации в документе.
источник
В Интернете протокол с отслеживанием состояния основан на наличии временного токена, которым обмениваются браузер и сервер (через заголовок cookie или перезапись URI) при каждом запросе. Этот токен обычно создается на стороне сервера и представляет собой кусок непрозрачного данных, у которых есть определенное время жизни, и его единственная цель - идентифицировать конкретного веб-агента пользователя. То есть токен является временным и становится СОСТОЯНИЕМ, которое веб-сервер должен поддерживать от имени клиентского пользовательского агента в течение этого разговора. Следовательно, такая связь с использованием токена НЕОБХОДИМА. И если диалог между клиентом и сервером СТАТИЧНЫЙ, это не RESTful.
Имя пользователя / пароль (отправленный в заголовке авторизации) обычно сохраняется в базе данных с целью идентификации пользователя. Иногда пользователь мог иметь в виду другое приложение; однако имя пользователя / пароль НИКОГДА предназначены для идентификации конкретного пользовательского агента веб-клиента. Разговор между веб-агентом и сервером, основанный на использовании имени пользователя и пароля в заголовке авторизации (после базовой авторизации HTTP), является БЕСПРОВОДНЫМ, потому что интерфейс веб-сервера не создает и не поддерживает какую-либо информацию о СОСТОЯНИИ.что бы то ни было от имени конкретного пользовательского агента веб-клиента. И, исходя из моего понимания REST, в протоколе четко указано, что диалог между клиентами и сервером должен быть БЕСПЛАТНЫМ. Следовательно, если мы хотим иметь настоящую службу RESTful, мы должны использовать имя пользователя / пароль (см. RFC, упомянутый в моем предыдущем сообщении) в заголовке авторизации для каждого отдельного вызова, а НЕ токен типа отправления (например, токены сеанса, созданные на веб-серверах. , Токены OAuth, созданные на серверах авторизации, и т. Д.).
Я понимаю, что несколько вызываемых REST-провайдеров используют токены, такие как OAuth1 или OAuth2 accept-tokens, которые передаются как «Авторизация: носитель» в заголовках HTTP. Однако мне кажется, что использование этих токенов для служб RESTful нарушит истинное БЕЗГРАНИЧНОЕ значение, которое охватывает REST; потому что эти токены представляют собой временный фрагмент данных, созданный / поддерживаемый на стороне сервера для идентификации конкретного пользовательского агента веб-клиента в течение допустимого периода разговора между веб-клиентом и сервером. Следовательно, любая служба, использующая эти токены OAuth1 / 2, не должна называться REST, если мы хотим придерживаться ИСТИННОГО значения протокола STATELESS.
Рубенс
источник