Tengo un cliente de servicio web Java, que consume un servicio web a través de HTTPS.
import javax.xml.ws.Service;
@WebServiceClient(name = "ISomeService", targetNamespace = "http://tempuri.org/", wsdlLocation = "...")
public class ISomeService
extends Service
{
public ISomeService() {
super(__getWsdlLocation(), ISOMESERVICE_QNAME);
}
Cuando me conecto a la URL del servicio ( https://AAA.BBB.CCC.DDD:9443/ISomeService
), obtengo la excepción java.security.cert.CertificateException: No subject alternative names present
.
Para solucionarlo, primero ejecuté openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt
y obtuve el siguiente contenido en el archivocerts.txt
:
CONNECTED(00000003)
---
Certificate chain
0 s:/CN=someSubdomain.someorganisation.com
i:/CN=someSubdomain.someorganisation.com
-----BEGIN CERTIFICATE-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----END CERTIFICATE-----
---
Server certificate
subject=/CN=someSubdomain.someorganisation.com
issuer=/CN=someSubdomain.someorganisation.com
---
No client certificate CA names sent
---
SSL handshake has read 489 bytes and written 236 bytes
---
New, TLSv1/SSLv3, Cipher is RC4-MD5
Server public key is 512 bit
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : RC4-MD5
Session-ID: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Session-ID-ctx:
Master-Key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Key-Arg : None
Start Time: 1382521838
Timeout : 300 (sec)
Verify return code: 21 (unable to verify the first certificate)
---
AFAIK, ahora necesito
- extraer la parte de
certs.txt
entre-----BEGIN CERTIFICATE-----
y-----END CERTIFICATE-----
, - modificarlo para que el nombre del certificado sea igual a
AAA.BBB.CCC.DDD
y - luego importe el resultado usando
keytool -importcert -file fileWithModifiedCertificate
(dondefileWithModifiedCertificate
es el resultado de las operaciones 1 y 2).
¿Es esto correcto?
Si es así, ¿cómo puedo hacer exactamente que el certificado del paso 1 funcione con una dirección basada en IP (AAA.BBB.CCC.DDD
)?
Actualización 1 (23.10.2013 15:37 MSK): En respuesta a una pregunta similar , leí lo siguiente:
Si no tiene el control de ese servidor, use su nombre de host (siempre que haya al menos un CN que coincida con ese nombre de host en el certificado existente).
¿Qué significa exactamente "usar"?
fuente
Tengo el mismo problema y lo resolví con este código. Pongo este código antes de la primera llamada a mis servicios web.
Es simple y funciona bien.
Aquí está la fuente original.
fuente
return hostname.equals("localhost");
, si eso es lo que desea hacer. Elif
es completamente superfluo.HttpsURLConnection connection = (HttpsURLConnection) obj.openConnection();
. Además, ¿esto ignora todos los certificados? Desde que vi que tal solución es vulnerable a la seguridad. ¡Gracias!Esta es una pregunta antigua, pero tuve el mismo problema al pasar de JDK 1.8.0_144 a jdk 1.8.0_191
Encontramos una pista en el registro de cambios:
Registro de cambios
Agregamos la siguiente propiedad adicional del sistema, que ayudó en nuestro caso a resolver este problema:
fuente
La verificación de la identidad del certificado se realiza contra lo que solicita el cliente.
Cuando su cliente usa
https://xxx.xxx.xxx.xxx/something
(dondexxx.xxx.xxx.xxx
está una dirección IP), la identidad del certificado se verifica con esta dirección IP (en teoría, solo se usa una extensión IP SAN).Si su certificado no tiene IP SAN, pero DNS SAN (o si no tiene DNS SAN, un nombre común en el DN del sujeto), puede hacer que esto funcione haciendo que su cliente use una URL con ese nombre de host en su lugar (o un nombre de host para el cual el certificado sería válido, si hay varios valores posibles). Por ejemplo, si cert tiene un nombre para
www.example.com
, usehttps://www.example.com/something
.Por supuesto, necesitará ese nombre de host para resolver esa dirección IP.
Además, si hay alguna SAN de DNS, se ignorará el CN en el DN del sujeto, así que utilice un nombre que coincida con una de las SAN de DNS en este caso.
fuente
http://www.example.com/someservice
. ¿Es correcto que para que el certificado funcione con la dirección basada en IP (https://AAA.BBB.CCC.DDD:9443/ISomeService
), necesito establecer todos losCN
campos enAAA.BBB.CCC.DDD
(reemplazarsomeSubdomain.someorganisation.com
porAAA.BBB.CCC.DDD
en el archivo anterior) e importar el archivo de certificado resultante?/etc/hosts
archivo o equivalentePara importar el certificado:
openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt
esto extraerá los certificados en formato PEM.openssl x509 -in certs.txt -out certs.der -outform DER
sudo keytool -importcert -file certs.der -keystore <path-to-cacerts>
contraseña predeterminada de cacerts es 'changeit'.Si el certificado se emite para un FQDN y está intentando conectarse por dirección IP en su código Java, entonces esto probablemente debería arreglarse en su código en lugar de jugar con el certificado en sí. Cambie su código para conectarse por FQDN. Si el FQDN no se puede resolver en su máquina de desarrollo, simplemente agréguelo a su archivo de hosts o configure su máquina con un servidor DNS que pueda resolver este FQDN.
fuente
Solucioné este problema de la manera correcta agregando los nombres alternativos del sujeto en el certificado en lugar de realizar cambios en el código o deshabilitar SSL a diferencia de lo que sugieren otras respuestas aquí. Si ve claramente, la excepción dice "Faltan los nombres alternativos del sujeto", por lo que la forma correcta debería ser agregarlos.
Mire este enlace para comprenderlo paso a paso .
El error anterior significa que a su archivo JKS le falta el dominio requerido en el que está intentando acceder a la aplicación. Deberá usar Open SSL y la herramienta clave para agregar varios dominios.
echo '[ subject_alt_name ]' >> openssl.cnf
echo 'subjectAltName = DNS:example.mydomain1.com, DNS:example.mydomain2.com, DNS:example.mydomain3.com, DNS: localhost'>> openssl.cnf
openssl req -x509 -nodes -newkey rsa:2048 -config openssl.cnf -extensions subject_alt_name -keyout private.key -out self-signed.pem -subj '/C=gb/ST=edinburgh/L=edinburgh/O=mygroup/OU=servicing/CN=www.example.com/[email protected]' -days 365
Exporte el archivo de clave pública (.pem) al formato PKS12. Esto le pedirá la contraseña
Crear un .JKS a partir de PEM autofirmado (almacén de claves)
Genere un certificado desde el archivo Keystore o JKS anterior
Dado que el certificado anterior está autofirmado y no está validado por CA, debe agregarse en Truststore (archivo Cacerts en la ubicación siguiente para MAC, para Windows, averigüe dónde está instalado su JDK).
Respuesta original publicada en este enlace aquí .
fuente
Es posible que no desee deshabilitar toda la verificación ssl y, por lo tanto, puede deshabilitar la verificación del nombre de host a través de esto, que es un poco menos aterrador que la alternativa:
[EDITAR]
Como lo menciona conapart3
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
ahora está en desuso, por lo que puede eliminarse en una versión posterior, por lo que es posible que en el futuro se vea obligado a lanzar la suya propia, aunque todavía diría que me alejaría de cualquier solución en la que toda la verificación esté desactivada.fuente
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
ahora está en desuso.mi problema para obtener este error se resolvió utilizando la URL completa "qatest.ourCompany.com/webService" en lugar de solo "qatest / webService". El motivo fue que nuestro certificado de seguridad tenía un comodín, es decir, "* .ourCompany.com". Una vez que ingresé la dirección completa, la excepción desapareció. Espero que esto ayude.
fuente
Ya lo he respondido en https://stackoverflow.com/a/53491151/1909708 .
Esto falla porque ni el nombre común del certificado (
CN
en la certificaciónSubject
) ni ninguno de los nombres alternativos (Subject Alternative Name
en el certificado) coinciden con el nombre de host o la dirección IP de destino.Por ejemplo, desde una JVM, al intentar conectarse a una dirección IP (
WW.XX.YY.ZZ
) y no al nombre DNS ( https://stackoverflow.com ), la conexión HTTPS fallará porque el certificado almacenado en el almacén de confianza de Javacacerts
espera un nombre común (o certificado nombre alternativo como stackexchange.com o * .stackoverflow.com, etc.) para que coincida con la dirección de destino.Consulte: https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#HostnameVerifier
Arriba, pasó un
HostnameVerifier
objeto implementado que siempre devuelvetrue
:fuente
Para Spring Boot
RestTemplate
:org.apache.httpcomponents.httpcore
dependenciautilizar
NoopHostnameVerifier
para la fábrica SSL:fuente
Llegué a esta pregunta después de recibir este mismo mensaje de error. Sin embargo, en mi caso, teníamos dos URL con diferentes subdominios ( http://example1.xxx.com/someservice y http://example2.yyy.com/someservice ) que estaban dirigidas al mismo servidor. Este servidor solo tenía un certificado comodín para el dominio * .xxx.com. Al usar el servicio a través del segundo dominio, el certificado encontrado (* .xxx.com) no coincide con el dominio solicitado (* .yyy.com) y se produce el error.
En este caso, no deberíamos intentar corregir dicho mensaje de error reduciendo la seguridad SSL, sino que deberíamos comprobar el servidor y los certificados que contiene.
fuente
fuente
Estaba pasando por SSL de 2 vías en Springboot. He hecho toda la configuración correcta del servidor Tomcat del servicio y del llamador RestTemplate del servicio. pero recibía un error como "java.security.cert.CertificateException: no hay nombres alternativos de sujeto presentes"
Después de revisar las soluciones, descubrí que JVM necesita este certificado, de lo contrario, da un error de protocolo de enlace.
Ahora, cómo agregar esto a JVM.
vaya al archivo jre / lib / security / cacerts. Necesitamos agregar nuestro archivo de certificado de servidor a este archivo cacerts de jvm.
Comando para agregar certificado de servidor al archivo cacerts a través de la línea de comando en Windows.
C: \ Archivos de programa \ Java \ jdk1.8.0_191 \ jre \ lib \ security> keytool -import -noprompt -trustcacerts -alias sslserver -file E: \ spring_cloud_sachin \ ssl_keys \ sslserver.cer -keystore cacerts -storepass changeit
Compruebe que el certificado del servidor esté instalado o no:
C: \ Archivos de programa \ Java \ jdk1.8.0_191 \ jre \ lib \ security> keytool -list -keystore cacerts
puede ver la lista de certificados instalados:
para más detalles: https://sachin4java.blogspot.com/2019/08/javasecuritycertcertificateexception-no.html
fuente
agregue la entrada de host con la ip correspondiente al CN en el certificado
CN = someSubdomain.someorganisation.com
ahora actualice la ip con el nombre CN donde está intentando acceder a la url.
Funcionó para mí.
fuente
fuente
Cuando tiene un certificado con CN y Nombres alternativos del sujeto (SAN), si realiza su solicitud en función del contenido CN, ese contenido en particular también debe estar presente en SAN; de lo contrario, fallará con el error en cuestión.
En mi caso, CN tenía algo, SAN tenía algo más. Tuve que usar SAN URL, y luego funcionó bien.
fuente
Agregue su dirección IP en el archivo de hosts, que se encuentra en la carpeta C: \ Windows \ System32 \ drivers \ etc. También agregue la IP y el Nombre de dominio de la dirección IP. ejemplo: aaa.bbb.ccc.ddd [email protected]
fuente
He resuelto el problema de la siguiente manera.
1. Creando una clase. La clase tiene algunas implementaciones vacías.
2. Creando un método
fuente