Веб-сервис RESTful - как аутентифицировать запросы от других служб?

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

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

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

  • Попросите клиентские службы использовать "поддельные" имя пользователя и пароль и аутентифицировать их так же, как и пользователи. Мне не нравится этот вариант - он просто не чувствует себя хорошо.

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

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

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

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

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

Ответ 1

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

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

Несмотря на всю эту "лучшую" дискуссию, позвольте мне указать, что есть еще одна философия, которая гласит: "меньше кода, меньше умения лучше". (Я лично придерживаюсь этой философии). Решение клиентского сертификата похоже на много кода.

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

Ответ 2

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

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

(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

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

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

:)

Ответ 3

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

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

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

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

Ответ 4

Я считаю, что подход:

  • Первый запрос, клиент отправляет id/passcode
  • Exchange id/pass для уникального токена
  • Проверять токен на каждый последующий запрос до истечения срока действия

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

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

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

Ответ 5

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

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

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

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

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

Ответ 6

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

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

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

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

https://jwt.io/introduction/

Ответ 7

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

  • Сначала подтвердите запрос REST: /authenticate. Возвращает ответ (в соответствии с вашим клиентским форматом) с помощью sessionId: ABCDXXXXXXXXXXXXXX;

  • Сохраните этот 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
    }
    
  • Получить sessionid с каждым вызовом REST, например URL?jsessionid=ABCDXXXXXXXXXXXXXX (или другим способом);

  • Извлеките HttpSession из карты с помощью sessionId;
  • Подтвердить запрос для этого сеанса, если сеанс активен;
  • Отправить ответ или сообщение об ошибке.

Ответ 8

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

Ответ 9

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