java - consumir - Autenticación mutua con servicios web.
web service con ssl (4)
En la actualidad, he implementado con éxito la seguridad de autenticación mutua siempre que el cliente acceda al sitio web mediante un navegador web, ya que los navegadores se encargan de todo el intercambio de certificados por usted. Ahora necesito crear una interfaz segura con la que los usuarios puedan acceder a los servicios web a través de HTTPS, utilizando la autenticación mutua requerida por el servidor.
En primer lugar, ¿hay algún recurso que alguien sepa que pueda ayudarme con esto? He buscado bastante tiempo y no he encontrado nada. ¿Algún otro consejo que alguien pueda darme sobre cómo hacer esto?
En segundo lugar, creo que mi mayor obstáculo es mi falta de comprensión de cómo manejar los certificados. ¿Cómo puedo negociar para aceptar la clave del servidor y presentar mi propia clave al servidor? Esto está en Java.
Para la autenticación mutua con SSL (también conocido como SSL de dos vías) fuera de un navegador, necesitará ... Bueno, en realidad, veamos primero lo que necesita para SSL de una sola vía:
- Un almacén de claves del servidor
- Un almacén de confianza del cliente
El almacén de claves del servidor contiene el certificado del servidor (posiblemente autofirmado) y la clave privada. El servidor utiliza esta tienda para firmar mensajes y devolver las credenciales al cliente.
El almacén de confianza del cliente contiene el certificado del servidor (autofirmado) (extraído del almacén de claves del servidor en un certificado independiente, sin la clave privada del servidor). Esto es necesario si el certificado no está firmado por una CA de confianza para la cual ya tiene un certificado en el almacén de confianza empaquetado con el JRE. Este paso permite crear una cadena de confianza.
Con esto, puede implementar SSL unidireccional (el caso de uso tradicional).
Para implementar SSL bidireccional, debe hacer esta configuración "simétrica", por lo que necesitaremos agregar:
- Un almacén de claves del cliente
- Un servidor de almacén de confianza
El almacén de claves del cliente contiene el certificado del cliente (posiblemente autofirmado) y la clave privada. El cliente utiliza esta tienda para el mismo propósito que el almacén de claves del servidor, es decir, para enviar las credenciales del cliente al servidor durante el protocolo de intercambio mutuo de autenticación TLS.
El almacén de confianza del servidor contiene los certificados independientes de los clientes (autofirmados) (extraídos de los almacenes de claves de los clientes en certificados independientes, sin la clave privada de los clientes). Esto se requiere por las mismas razones que se mencionaron anteriormente.
Algunos recursos para ayudarlo a generar todo esto y para implementar las soluciones finales:
Pasé mucho tiempo en esto, pero finalmente encontré un ejemplo que realmente funciona. Está basado en Glassfish y Netbeans, pero creo que podría hacerlo funcionar en otros entornos (por ejemplo, Eclipse y Tomcat) si jugó con él.
http://java.sun.com/webservices/reference/tutorials/wsit/doc/WSIT_Security9.html#wp162511
El problema que he encontrado es cuando quieres usar tus propios certificados, no los que vienen preinstalados con glassfish.
Nota: No soy un experto en seguridad. ¡No despliegue esto en un entorno de producción!
Para hacer esto, estoy usando NetBeans 6.9, JDK 1.6, GlassFish 3.0.1 y OpenSSL v1.0 (estoy usando los binarios no oficiales de 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"
En la consola de administración de GlassFish, habilite la Seguridad en su http-listener, marque los cuadros SSL3, TLS y Autenticación del cliente, establezca el Nickname del certificado en el servidor, el almacén de claves en config / keystore.jks, el Trust Store en config / keystore.jks , el algoritmo de confianza a PKIX y deja la longitud máxima del certificado en 5.
En NetBeans, crea un nuevo proyecto de aplicación web. Dentro de eso, crea un nuevo servicio web.
Mi código de servicio web se parecía a esto:
@WebService()
public class ListProducts {
@Resource WebServiceContext context;
@WebMethod(operationName = "listProducts")
public String listProducts() {
return context.getUserPrincipal().toString();
}
}
Haga clic derecho en el servicio web y seleccione Editar atributos del servicio web. Marque la casilla Servicio seguro y seleccione Seguridad de certificados mutuos como el Mecanismo de seguridad. Haga clic en el botón Configurar ... y marque la casilla Encriptar firma. Ahora desmarque la casilla Usar valores predeterminados de desarrollo y luego haga clic en el botón Almacén de claves. Establezca la ubicación de su almacén de claves server.jks y seleccione el alias del server
. Haga lo mismo para la configuración de Truststore (aunque no tiene que seleccionar un alias aquí).
Importe el certificado de cliente client1.p12 en su navegador. Implementar su servicio web a Glassfish. Abra su servicio web en un navegador y busque el WSDL implementado a través de HTTPS. Descarga el WSDL y cualquier otro esquema. Cambie el nombre de los esquemas referenciados a copias locales para que cuando use WSDL2Java NetBeans no use ningún recurso remoto. (Este párrafo se debe a que ha restringido su WSDL a clientes con un certificado aprobado, pero NetBeans no puede obtenerlo de forma remota porque no tiene acceso al certificado en cuestión).
Crear un nuevo proyecto de Java. Crear un nuevo cliente de servicio web. Cuando se le solicite, apunte NetBeans a su archivo WSDL guardado. Importe los archivos de la biblioteca METRO2.0 ( C:/Program Files/Netbeans 6.9/enterprise/modules/ext/metr/webservices-*.jar
). Mi código se veía así:
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());
}
Copie webservices-api.jar en su directorio Java / jdk1.6 / jre / lib / endosed. Haga clic con el botón derecho en la referencia del servicio web y seleccione Editar atributos del servicio web. Establezca la ubicación del almacén de claves en client1.jks y establezca el alias en client1
. Establezca la ubicación del almacén de confianza en client1.jks y configure el alias al server
.
Esperemos que ahora pueda ejecutar su cliente y debería ver el resultado de este modo: [email protected], CN=Bob Smith, OU=Something, O=SomethingElse, L=AnyTown, ST=AnyState, C=US
Si la biblioteca de servicios web utiliza la clase java.net.URL
estándar como un cliente HTTP, puede configurar algunas propiedades del sistema y la autenticación bidireccional será manejada por el soporte HTTPS incorporado.
Las propiedades necesarias son:
-
javax.net.ssl.trustStore
: contiene certificados de CA raíz -
javax.net.ssl.keyStore
: contiene certificado de cliente y clave privada -
javax.net.ssl.keyStorePassword
: la contraseña que protege la clave privada del cliente
Estas configuraciones se convierten en los valores predeterminados para todas las conexiones SSL según el proceso. Si desea un control más SSLContext
, debe configurar su propio SSLContext
. Si eso es posible con el tiempo de ejecución de su servicio web, depende del tiempo de ejecución que haya elegido.
Una receta simple se da en esta entrada de blog .
Pero creo que la respuesta real puede depender de qué API de Java está utilizando para implementar las interacciones HTTP del lado del cliente. Por ejemplo, parece que harías las cosas de manera diferente usando JAX-RPC.