Взаимная аутентификация с веб-сервисами - PullRequest
22 голосов
/ 11 февраля 2010

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

Прежде всего, есть ли какие-нибудь источники, которые могут мне помочь? Я долго искал и ничего не нашел. Любые другие советы, которые кто-нибудь может дать мне о том, как это сделать?

Во-вторых, я думаю, что моим самым большим препятствием является мое непонимание того, как обращаться с сертификатами. Как договориться о том, чтобы принять ключ сервера и представить свой собственный ключ серверу? Это на Яве.

Ответы [ 4 ]

14 голосов
/ 27 мая 2010

Я потратил много времени на это, но я наконец нашел пример, который действительно работает. Он основан на Glassfish и Netbeans, но я думаю, вы могли бы заставить его работать в других средах (например, Eclipse и Tomcat), если поигрались с ним.

http://java.sun.com/webservices/reference/tutorials/wsit/doc/WSIT_Security9.html#wp162511

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

Примечание: я не эксперт по безопасности. Не развертывайте это в производственной среде!

Для этого я использую NetBeans 6.9, JDK 1.6, GlassFish 3.0.1 и OpenSSL v1.0 (я использую неофициальные бинарные файлы Win32)

# Create the CA
mkdir ca server client
cd ca
openssl req -new -x509 -days 3650 -extensions v3_ca -keyout ca.key -out ca.pem
echo 02 > serial.txt
cd ..

# Creating the Server Keystore

openssl req -days 3650 -newkey rsa:1024 -keyout server/server.key -out server/server.req
openssl x509 -extensions usr_cert -extfile C:\testbed\OpenSSL-Win32\bin\openssl.cfg -CA ca/ca.pem -CAkey ca/ca.key -CAserial ca/serial.txt -req -in server/server.req -out server/server.crt
openssl pkcs12 -export -inkey server/server.key -in server/server.crt -out server/server.p12 -name server
keytool -importkeystore -destkeystore server/server.jks -deststoretype jks -srckeystore server/server.p12 -srcstoretype pkcs12
keytool -exportcert -alias server -keystore server/server.jks -file server/server.cer

# Create the Client Keystore

openssl req -days 3650 -newkey rsa:1024 -keyout client/client1.key -out client/client1.req
openssl x509 -extensions usr_cert -extfile C:\testbed\OpenSSL-Win32\bin\openssl.cfg -CA ca/ca.pem -CAkey ca/ca.key -CAserial ca/serial.txt -req -in client/client1.req -out client/client1.crt
openssl pkcs12 -export -inkey client/client1.key -in client/client1.crt -out client/client1.p12 -name client1
keytool -importkeystore -destkeystore client/client1.jks -deststoretype jks -srckeystore client/client1.p12 -srcstoretype pkcs12
keytool -exportcert -alias client1 -keystore client/client1.jks -file client/client1.cer

# Import public keys and certificates into each others keystores

keytool -import -noprompt -trustcacerts -alias client1 -file client/client1.cer -keystore server/server.jks
keytool -import -noprompt -trustcacerts -alias server -file server/server.cer -keystore client/client1.jks
keytool -import -noprompt -trustcacerts -alias my_ca -file ca/ca.pem -keystore server/server.jks
keytool -import -noprompt -trustcacerts -alias my_ca -file ca/ca.pem -keystore client/client1.jks
keytool -import -noprompt -trustcacerts -alias my_ca -file ca/ca.pem -keystore "C:\Program Files\glassfish-3.0.1\glassfish\domains\domain1\config\cacerts.jks"
keytool -import -noprompt -trustcacerts -alias my_ca -file ca/ca.pem -keystore "C:\Program Files\Java\jdk1.6\jre\lib\security\cacerts"
move "C:\Program Files\glassfish-3.0.1\glassfish\domains\domain1\config\keystore.jks" "C:\Program Files\glassfish-3.0.1\glassfish\domains\domain1\config\keystore.jks.backup"
copy server\server.jks "C:\Program Files\glassfish-3.0.1\glassfish\domains\domain1\config\keystore.jks"

В консоли администратора GlassFish включите Security на своем http-слушателе, отметьте поля SSL3, TLS и Client Authentication, задайте для NickName сертификата сервер, хранилище ключей для config \ keystore.jks, хранилище доверенных сертификатов для config \ keystore.jks, алгоритм доверия для PKIX и оставьте максимальную длину сертификата на уровне 5.

В NetBeans создайте новый проект веб-приложения. В рамках этого создайте новый веб-сервис.

Код моего веб-сервиса выглядел так:

@WebService()
public class ListProducts {

  @Resource WebServiceContext context;

  @WebMethod(operationName = "listProducts")
  public String listProducts() {
    return context.getUserPrincipal().toString();
  }

}

Щелкните правой кнопкой мыши веб-службу и выберите «Изменить атрибуты веб-службы». Установите флажок Безопасное обслуживание и выберите Безопасность взаимных сертификатов в качестве механизма безопасности. Нажмите кнопку «Настроить ...» и установите флажок «Зашифровать подпись». Теперь снимите флажок «Использовать параметры разработки по умолчанию» и нажмите кнопку «Keystore». Установите местоположение вашего хранилища ключей server.jks и выберите псевдоним server. Сделайте то же самое для конфигурации хранилища доверенных сертификатов (хотя здесь вам не нужно выбирать псевдоним).

Импортируйте клиентский сертификат client1.p12 в ваш браузер. Разверните свой веб-сервис на Glassfish. Откройте веб-службу в браузере и перейдите к развернутому WSDL через HTTPS. Загрузите WSDL и любые другие схемы. Переименуйте любые ссылочные схемы в локальные копии, чтобы при использовании WSDL2Java NetBeans не использовал никакие удаленные ресурсы. (Этот абзац объясняется тем, что вы ограничивали свой WSDL для клиентов с утвержденным сертификатом, но NetBeans не может извлечь его удаленно, поскольку у него нет доступа к рассматриваемому сертификату).

Создать новый проект Java. Создайте новый клиент веб-службы. При появлении запроса укажите NetBeans на сохраненный файл WSDL. Импортируйте файлы библиотеки METRO2.0 (C:\Program Files\Netbeans 6.9\enterprise\modules\ext\metr\webservices-*.jar). Мой код выглядел так:

public static void main(String[] args) {
  System.getProperties().put("javax.net.ssl.keyStore", "C:\\NetBeansProjects\\security-04\\ssl\\client\\client1.jks");
  System.getProperties().put("javax.net.ssl.keyStorePassword", "changeit");
  System.getProperties().put("javax.net.ssl.trustStore", "C:\\NetBeansProjects\\security-04\\ssl\\client\\client1.jks");
  System.getProperties().put("javax.net.ssl.trustStorePassword", "changeit");
  System.out.println(new ListProductsService().getListProductsPort().listProducts());
}

Скопируйте файл webservices-api.jar в каталог Java \ jdk1.6 \ jre \ lib \ endorsed. Щелкните правой кнопкой мыши ссылку на веб-службу и выберите «Изменить атрибуты веб-службы». Задайте местоположение хранилища ключей для client1.jks и установите псевдоним client1. Задайте расположение хранилища доверенных сертификатов для client1.jks и установите псевдоним server.

Надеюсь, теперь вы можете запустить свой клиент, и вы должны увидеть результат примерно так: EMAILADDRESS=bob@anonymous.org, CN=Bob Smith, OU=Something, O=SomethingElse, L=AnyTown, ST=AnyState, C=US

13 голосов
/ 11 февраля 2010

Для взаимной аутентификации с использованием SSL (он же двусторонний SSL) вне браузера вам понадобится ... Ну, собственно, давайте сначала посмотрим, что нужно для одностороннего SSL:

  1. Хранилище ключей сервера
  2. Клиентское доверенное хранилище

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

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

С этим вы можете реализовать односторонний SSL (традиционный вариант использования).

Чтобы реализовать двусторонний SSL, вам нужно сделать эту настройку "симметричной", поэтому нам нужно добавить:

  1. Клиентское хранилище ключей
  2. Склад доверенных сертификатов

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

Хранилище доверенных сертификатов сервера содержит автономные сертификаты клиентов (самозаверяющие) (извлекаемые из хранилища ключей клиентов в автономные сертификаты без закрытого ключа клиентов). Это необходимо по тем же причинам, что и ранее.

Некоторые ресурсы, которые помогут вам сгенерировать весь этот материал и реализовать окончательные решения:

6 голосов
/ 11 февраля 2010

Если библиотека веб-службы использует стандартный класс java.net.URL в качестве клиента HTTP, вы можете установить некоторые системные свойства , и двусторонняя аутентификация будет обрабатываться встроенной поддержкой HTTPS. 1004 *

необходимые свойства :

  • javax.net.ssl.trustStore: содержит сертификаты корневого ЦС
  • javax.net.ssl.keyStore: содержит сертификат клиента и закрытый ключ
  • javax.net.ssl.keyStorePassword: пароль, защищающий закрытый ключ клиента

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

1 голос
/ 11 февраля 2010

Простой рецепт дан в этой записи блога .

Но я думаю, что реальный ответ может зависеть от того, какие API Java вы используете для реализации ваших HTTP-взаимодействий на стороне клиента. Например, похоже, что вы будете делать вещи немного по-другому , используя JAX-RPC.

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