Веб-сервис RESTful - как аутентифицировать запросы от других сервисов? - PullRequest
113 голосов
/ 26 мая 2011

Я разрабатываю веб-сервис RESTful, к которому должны обращаться пользователи, а также другие веб-сервисы и приложения. Все входящие запросы должны быть аутентифицированы. Все общение происходит по HTTPS. Аутентификация пользователя будет работать на основе токена аутентификации, полученного путем отправки имени пользователя и пароля (через соединение SSL) в ресурс / session , предоставляемый службой.

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

Варианты, которые я могу придумать (или мне предложили):

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

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

  3. Я мог бы добавить проверку IP-адреса к предыдущей опции. Это усложнит выполнение ложных запросов.

  4. Клиентские сертификаты. Установите свой собственный центр сертификации, создайте корневой сертификат и создайте клиентские сертификаты для клиентских служб. Однако на ум приходит пара вопросов: а) как мне разрешить пользователям проходить аутентификацию без сертификатов и б) насколько сложно реализовать этот сценарий с точки зрения обслуживания клиентов?

  5. Что-то еще - должны быть другие решения?

Мой сервис будет работать на Java, но я намеренно пропустил информацию о том, на какой конкретной платформе он будет построен, потому что меня больше интересуют базовые принципы, а не подробности реализации - я предполагаю лучшее решение для этого будет возможно реализовать независимо от базовой структуры. Однако я немного неопытен в этом вопросе, поэтому конкретные советы и примеры по фактической реализации (такие как полезные сторонние библиотеки, статьи и т. Д.) Также будут высоко оценены.

Ответы [ 9 ]

35 голосов
/ 03 июня 2011

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

Вот пример для создания токена аутентификации:

(day * 10) + (month * 100) + (year (last 2 digits) * 1000)

например: 3 июня 2011 года

(3 * 10) + (6 * 100) + (11 * 1000) = 
30 + 600 + 11000 = 11630

затем соедините с паролем пользователя, например, "my4wesomeP4ssword!"

11630my4wesomeP4ssword!

Затем выполните MD5 из этой строки:

05a9d022d621b64096160683f3afe804

Когда вы вызываете запрос, всегда используйте этот токен,

https://mywebservice.com/?token=05a9d022d621b64096160683f3afe804&op=getdata

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

Надежда помогает

:)

32 голосов
/ 02 июня 2011

Любое решение этой проблемы сводится к общему секрету. Мне также не нравится жестко заданная опция имени пользователя и пароля, но она имеет преимущество, заключающееся в простоте. Сертификат клиента также хорош, но действительно ли он сильно отличается? Есть сертификат на сервере и один на клиенте. Главное его преимущество в том, что грубую силу сложнее. Надеюсь, у вас есть другие средства защиты от этого.

Я не думаю, что вашу точку A для решения по сертификату клиента трудно решить. Вы просто используете ветку. if (client side certificat) { check it } else { http basic auth } Я не эксперт по Java, и я никогда не работал с ним для создания сертификатов на стороне клиента. Однако быстрый Google приводит нас к этому уроку , который смотрит прямо на вашу аллею.

Несмотря на все это обсуждение «что лучше», позвольте мне отметить, что есть другая философия, которая гласит: «Чем меньше кода, тем меньше умнее». (Лично я придерживаюсь этой философии). Решение для клиентского сертификата звучит как много кода.

Я знаю, что вы высказали вопросы об OAuth, но предложение OAuth2 действительно включает решение вашей проблемы под названием " токены на предъявителя ", которое необходимо использовать вместе с SSL. Я думаю, для простоты, я бы выбрал либо жестко запрограммированного пользователя / проход (по одному на приложение, чтобы их можно было отозвать по отдельности), либо очень похожие токены на предъявителя.

11 голосов
/ 26 мая 2011

Существует несколько различных подходов.

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

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

  3. Из вашего описания действительно звучит так, как будто вас может заинтересовать OAuth2 По моему опыту, насколько я знаю, это довольно запутанно, и в некотором роде , Есть реализации, но они немногочисленны. Я понимаю, что в Java он был интегрирован в модули security Spring3. (Их учебник хорошо написан.) Я ждал, чтобы увидеть, будет ли расширение в Restlet , но пока, хотя оно было предложено, и может быть в инкубатор, он все еще не полностью включен.

3 голосов
/ 13 мая 2016

5. Что-то еще - должны быть другие решения?

Ты прав, есть! И он называется JWT (JSON Web Tokens).

JSON Web Token (JWT) - это открытый стандарт (RFC 7519), который определяет компактный и автономный способ безопасной передачи информации между сторонами в виде объекта JSON. Эта информация может быть проверена и надежна, потому что она имеет цифровую подпись. JWT могут быть подписаны с использованием секретного (с алгоритмом HMAC) или пары открытого / секретного ключей с использованием RSA.

Я настоятельно рекомендую изучить JWT. Это гораздо более простое решение проблемы по сравнению с альтернативными решениями.

https://jwt.io/introduction/

3 голосов
/ 03 июня 2011

Что касается подхода с использованием клиентских сертификатов, его будет не так уж сложно реализовать, но при этом разрешить доступ пользователям без клиентских сертификатов.

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

В зависимости от того, какой веб-сервер вы используете, должен быть способ указания аутентификации клиента, который будет принимать сертификат клиента, но не требует его. Например, в Tomcat при указании коннектора https вы можете установить «clientAuth = want» вместо «true» или «false». Затем вы должны обязательно добавить свой самозаверяющий сертификат CA в хранилище доверенных сертификатов (по умолчанию файл cacerts в используемой вами JRE, если только вы не указали другой файл в конфигурации своего веб-сервера), поэтому единственными доверенными сертификатами будут те, которые были выданы из Ваша собственная подпись CA.

На стороне сервера вы разрешаете доступ к службам, которые хотите защитить, только если вы можете получить сертификат клиента из запроса (не ноль) и проходить любые проверки DN, если вы предпочитаете какой-либо дополнительный уровень безопасности. Для пользователей без клиентских сертификатов они все равно смогут получить доступ к вашим услугам, но в запросе просто не будет сертификатов.

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

3 голосов
/ 01 июня 2011

Я верю подходу:

  1. Первый запрос, клиент отправляет идентификатор / код доступа
  2. Обмен ID / прохода для уникального токена
  3. Проверять токен на каждом последующем запросе до истечения срока его действия

является довольно стандартным, независимо от того, как вы реализуете и других конкретных технических деталей.

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

Надеюсь, это поможет

1 голос
/ 06 октября 2012

Вы можете создать сеанс на сервере и совместно использовать sessionId между клиентом и сервером при каждом вызове REST.

  1. Первая проверка подлинности REST-запроса: /authenticate.Возвращает ответ (в соответствии с форматом вашего клиента) с sessionId: ABCDXXXXXXXXXXXXXX;

  2. Сохраните это sessionId в Map с фактическим сеансом.Map.put(sessionid, session) или используйте SessionListener для создания и уничтожения ключей для вас;

    public void sessionCreated(HttpSessionEvent arg0) {
      // add session to a static Map 
    }
    
    public void sessionDestroyed(HttpSessionEvent arg0) {
      // Remove session from static map
    }
    
  3. Получить sessionid при каждом вызове REST, например URL?jsessionid=ABCDXXXXXXXXXXXXXX (или другим способом);

  4. Извлечение HttpSession из карты с использованием sessionId;
  5. Проверка запроса для этого сеанса, если сеанс активен;
  6. Отправка ответа или сообщения об ошибке.
0 голосов
/ 26 мая 2011

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

0 голосов
/ 26 мая 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...