Eu tenho um cliente de serviço web Java, que consome um serviço web via 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);
}
Quando me conecto ao URL do serviço ( https://AAA.BBB.CCC.DDD:9443/ISomeService
), recebo a exceção java.security.cert.CertificateException: No subject alternative names present
.
Para corrigi-lo, primeiro executei openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt
e obtive o seguinte conteúdo no arquivo certs.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, agora eu preciso
- extraia a parte
certs.txt
entre-----BEGIN CERTIFICATE-----
e-----END CERTIFICATE-----
, - modifique-o para que o nome do certificado seja igual a
AAA.BBB.CCC.DDD
e - em seguida, importe o resultado usando
keytool -importcert -file fileWithModifiedCertificate
(ondefileWithModifiedCertificate
é o resultado das operações 1 e 2).
Isso está correto?
Em caso afirmativo, como exatamente posso fazer o certificado da etapa 1 funcionar com endereço baseado em IP ( AAA.BBB.CCC.DDD
)?
Atualização 1 (23/10/2013 15:37 MSK): Em uma resposta a uma pergunta semelhante , li o seguinte:
Se você não estiver no controle desse servidor, use seu nome de host (desde que haja pelo menos um CN correspondente a esse nome de host no certificado existente).
O que exatamente significa "usar"?
fonte
Estou com o mesmo problema e resolvi com este código. Eu coloquei esse código antes da primeira chamada para meus serviços da web.
É simples e funciona bem.
Aqui está a fonte original.
fonte
return hostname.equals("localhost");
, se é isso que deseja fazer. Oif
é completamente supérfluo.HttpsURLConnection connection = (HttpsURLConnection) obj.openConnection();
. Além disso, isso ignora todos os certificados? Desde que vi que essa solução alternativa é vulnerável à segurança. Obrigado!Esta é uma pergunta antiga, mas eu tive o mesmo problema ao mudar de JDK 1.8.0_144 para jdk 1.8.0_191
Encontramos uma dica no changelog:
Changelog
adicionamos a seguinte propriedade de sistema adicional, que ajudou em nosso caso a resolver esse problema:
fonte
A verificação da identidade do certificado é realizada em relação ao que o cliente solicita.
Quando o seu cliente usa
https://xxx.xxx.xxx.xxx/something
(ondexxx.xxx.xxx.xxx
é um endereço IP), a identidade do certificado é verificada em relação a este endereço IP (em teoria, usando apenas uma extensão IP SAN).Se o seu certificado não tem SAN IP, mas SANs DNS (ou se não SANs DNS, um nome comum no DN do assunto), você pode fazer isso funcionar fazendo seu cliente usar um URL com esse nome de host (ou um nome de host para o qual o cert seria válido, se houver vários valores possíveis). Por exemplo, se você cert tem um nome para
www.example.com
, usehttps://www.example.com/something
.Claro, você precisará desse nome de host para resolver esse endereço IP.
Além disso, se houver SANs DNS, o CN no DN do assunto será ignorado, portanto, use um nome que corresponda a um dos SANs DNS neste caso.
fonte
http://www.example.com/someservice
. É correto que, para que o certificado funcione com endereço baseado em IP (https://AAA.BBB.CCC.DDD:9443/ISomeService
), eu preciso definir todos osCN
campos comoAAA.BBB.CCC.DDD
(substituirsomeSubdomain.someorganisation.com
porAAA.BBB.CCC.DDD
no arquivo acima) e importar o arquivo de certificado resultante?/etc/hosts
arquivo ou equivalentePara importar o certificado:
openssl s_client -showcerts -connect AAA.BBB.CCC.DDD:9443 > certs.txt
isso irá extrair certificados no formato PEM.openssl x509 -in certs.txt -out certs.der -outform DER
sudo keytool -importcert -file certs.der -keystore <path-to-cacerts>
A senha cacerts padrão é 'changeit'.Se o certificado for emitido para um FQDN e você estiver tentando se conectar por endereço IP em seu código Java, isso provavelmente deve ser corrigido em seu código, em vez de mexer com o próprio certificado. Altere seu código para se conectar por FQDN. Se o FQDN não puder ser resolvido em sua máquina de desenvolvimento, basta adicioná-lo ao arquivo hosts ou configurar sua máquina com um servidor DNS que possa resolver esse FQDN.
fonte
Corrigi esse problema de maneira correta adicionando os nomes alternativos do assunto no certificado, em vez de fazer qualquer alteração no código ou desabilitar o SSL, ao contrário do que outras respostas sugerem aqui. Se você vir claramente, a exceção diz "Faltam nomes alternativos de assunto", portanto, a maneira certa deve ser adicioná-los
Por favor, olhe este link para entender passo a passo .
O erro acima significa que seu arquivo JKS não tem o domínio necessário no qual você está tentando acessar o aplicativo. Você precisará usar Open SSL e a ferramenta-chave para adicionar vários domínios
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 o arquivo de chave pública (.pem) para o formato PKS12. Isso irá solicitar a senha
Crie um.JKS a partir de PEM autoassinado (Keystore)
Gerar um certificado do Keystore ou arquivo JKS acima
Como o certificado acima é autoassinado e não é validado pela CA, ele precisa ser adicionado ao Truststore (arquivo Cacerts no local abaixo para MAC, para Windows, descubra onde seu JDK está instalado).
Resposta original postada neste link aqui .
fonte
Você pode não querer desabilitar toda a verificação SSL e, portanto, pode simplesmente desabilitar a verificação hostName por meio disso, o que é um pouco menos assustador do que a alternativa:
[EDITAR]
Conforme mencionado por conapart3,
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
agora está obsoleto, por isso pode ser removido em uma versão posterior, então você pode ser forçado no futuro a lançar o seu próprio, embora eu ainda diria que evitaria qualquer solução em que toda a verificação fosse desligada.fonte
SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER
agora está obsoleto.meu problema em obter esse erro foi resolvido usando o URL completo "qatest.ourCompany.com/webService" em vez de apenas "qatest / webService". O motivo era que nosso certificado de segurança tinha um caractere curinga, ou seja, "* .nossa empresa.com". Assim que coloquei o endereço completo, a exceção foi embora. Espero que isto ajude.
fonte
Já respondi em https://stackoverflow.com/a/53491151/1909708 .
Isso falha porque nem o nome comum do certificado (
CN
na certificaçãoSubject
) nem qualquer um dos nomes alternativos (Subject Alternative Name
no certificado) correspondem ao nome do host de destino ou ao endereço IP.Por exemplo, a partir de uma JVM, ao tentar se conectar a um endereço IP (
WW.XX.YY.ZZ
) e não ao nome DNS ( https://stackoverflow.com ), a conexão HTTPS falhará porque o certificado armazenado no armazenamento confiável javacacerts
espera um nome comum (ou nome alternativo do certificado, como stackexchange.com ou * .stackoverflow.com etc.) para corresponder ao endereço de destino.Verifique: https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#HostnameVerifier
Acima, passou um
HostnameVerifier
objeto implementado que sempre retornatrue
:fonte
Para Spring Boot
RestTemplate
:org.apache.httpcomponents.httpcore
dependênciausar
NoopHostnameVerifier
para fábrica SSL:fonte
Eu cheguei a essa pergunta depois se recebi essa mesma mensagem de erro. No entanto, no meu caso, tínhamos dois URLs com subdomínios diferentes ( http://example1.xxx.com/someservice e http://example2.yyy.com/someservice ) que foram direcionados para o mesmo servidor. Este servidor tinha apenas um certificado curinga para o domínio * .xxx.com. Ao usar o serviço por meio do segundo domínio, o certificado encontrado (* .xxx.com) não corresponde ao domínio solicitado (* .yyy.com) e o erro ocorre.
Nesse caso, não devemos tentar consertar tal mensagem de erro diminuindo a segurança SSL, mas devemos verificar o servidor e os certificados nele.
fonte
fonte
Eu estava passando por SSL de 2 vias no springboot. Eu fiz toda a configuração correta do servidor tomcat do serviço e do chamador do serviço RestTemplate. mas eu estava recebendo um erro como "java.security.cert.CertificateException: Nenhum nome alternativo de assunto presente"
Depois de passar pelas soluções, descobri, a JVM precisa desse certificado, caso contrário, dá erro de handshaking.
Agora, como adicionar isso ao JVM.
vá para o arquivo jre / lib / security / cacerts. precisamos adicionar nosso arquivo de certificado do servidor a este arquivo cacerts de jvm.
Comando para adicionar certificado de servidor ao arquivo cacerts via linha de comando no Windows.
C: \ Arquivos de programas \ 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
Verifique se o certificado do servidor está instalado ou não:
C: \ Arquivos de programas \ Java \ jdk1.8.0_191 \ jre \ lib \ security> keytool -list -keystore cacerts
você pode ver a lista de certificados instalados:
para mais detalhes: https://sachin4java.blogspot.com/2019/08/javasecuritycertcertificateexception-no.html
fonte
adicione a entrada do host com o ip correspondente ao CN no certificado
CN = someSubdomain.someorganisation.com
agora atualize o ip com o nome CN onde você está tentando acessar a url.
Funcionou para mim
fonte
fonte
Quando você tem um certificado com CN e nomes alternativos de assunto (SAN), se você fizer sua solicitação com base no conteúdo CN, esse conteúdo específico também deverá estar presente no SAN, caso contrário, falhará com o erro em questão.
No meu caso, CN tinha algo, SAN tinha algo mais. Tive que usar o URL da SAN e funcionou perfeitamente.
fonte
Adicione seu endereço IP no arquivo hosts.que está na pasta C: \ Windows \ System32 \ drivers \ etc. Adicione também o IP e o nome de domínio do endereço IP. exemplo: aaa.bbb.ccc.ddd [email protected]
fonte
Resolvi o problema da seguinte maneira.
1. Criação de uma classe. A classe tem algumas implementações vazias
2. Criação de um método
fonte