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


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

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

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

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

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

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

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

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

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

9 105

9 ответов:

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

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

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

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

вот пример из to generate authentication token:

(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.

надеюсь поможет

:)

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

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

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

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

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

  1. первый запрос, клиент отправляет id / passcode
  2. обмен id / pass на уникальный токен
  3. проверять токен на каждом последующем запросе, пока он не истечет

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

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

надеюсь, что это помогает

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

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

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

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

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

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

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

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

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

https://jwt.io/introduction/

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

  1. первый запрос Аутентификации REST:/authenticate. Возвращает ответ (в соответствии с вашим форматом клиента) с sessionId: ABCDXXXXXXXXXXXXXX;

  2. магазин этот sessionId in 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. Retrive HttpSession С помощью карты sessionId;
  5. проверить запрос для этого сеанса, если сеанс активен;
  6. отправить ответ или сообщение об ошибке.

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

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