Estou com um problema de conexão SSL autorizada. Criei o Struts Action que se conecta ao servidor externo com o certificado SSL autorizado pelo cliente. Na minha ação, estou tentando enviar alguns dados para o servidor do banco, mas sem sorte, porque, como resultado do servidor, tenho o seguinte erro:
error: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Meu método da classe Action que envia dados para o servidor
//Getting external IP from host
URL whatismyip = new URL("http://automation.whatismyip.com/n09230945.asp");
BufferedReader inIP = new BufferedReader(new InputStreamReader(whatismyip.openStream()));
String IPStr = inIP.readLine(); //IP as a String
Merchant merchant;
System.out.println("amount: " + amount + ", currency: " + currency + ", clientIp: " + IPStr + ", description: " + description);
try {
merchant = new Merchant(context.getRealPath("/") + "merchant.properties");
} catch (ConfigurationException e) {
Logger.getLogger(HomeAction.class.getName()).log(Level.INFO, "message", e);
System.err.println("error: " + e.getMessage());
return ERROR;
}
String result = merchant.sendTransData(amount, currency, IPStr, description);
System.out.println("result: " + result);
return SUCCESS;
Meu arquivo merchant.properties:
bank.server.url=https://-servernameandport-/
https.cipher=-cipher-
keystore.file=-key-.jks
keystore.type=JKS
keystore.password=-password-
ecomm.server.version=2.0
encoding.source=UTF-8
encoding.native=UTF-8
Pela primeira vez, pensei que fosse um problema de certificado, converti-o de .pfx para .jks, mas tenho o mesmo erro, sem alterações.
Respostas:
A falha do aperto de mão pode ter ocorrido devido a vários motivos:
Como a falha subjacente não pode ser identificada, é melhor ativar o
-Djavax.net.debug=all
sinalizador para ativar a depuração da conexão SSL estabelecida. Com a depuração ativada, você pode identificar qual atividade do handshake falhou.Atualizar
Com base nos detalhes agora disponíveis, parece que o problema ocorre devido a um caminho incompleto de confiança do certificado entre o certificado emitido para o servidor e uma CA raiz. Na maioria dos casos, isso ocorre porque o certificado da CA raiz está ausente no armazenamento confiável, levando à situação em que um caminho de confiança do certificado não pode existir; o certificado é essencialmente não confiável pelo cliente. Os navegadores podem apresentar um aviso para que os usuários possam ignorar isso, mas o mesmo não acontece com clientes SSL (como a classe HttpsURLConnection ou qualquer biblioteca de clientes HTTP como Apache HttpComponents Client ).
A maioria dessas classes / bibliotecas cliente dependeria do armazenamento confiável usado pela JVM para validação de certificado. Na maioria dos casos, esse será o
cacerts
arquivo no diretório JRE_HOME / lib / security. Se o local do armazenamento confiável tiver sido especificado usando a propriedade do sistema JVMjavax.net.ssl.trustStore
, o armazenamento nesse caminho geralmente será o usado pela biblioteca do cliente. Em caso de dúvida, dê uma olhada na suaMerchant
turma e descubra a turma / biblioteca que ela está usando para fazer a conexão.Adicionar o certificado do servidor que emite a CA a esse armazenamento confiável deve resolver o problema. Você pode consultar minha resposta em uma pergunta relacionada sobre como obter ferramentas para essa finalidade, mas o utilitário Java keytool é suficiente para essa finalidade.
Aviso : O armazenamento confiável é essencialmente a lista de todas as CAs em que você confia. Se você inserir um certificado que não pertence a uma CA na qual não confia, as conexões SSL / TLS com sites com certificados emitidos por essa entidade poderão ser descriptografadas se a chave privada estiver disponível.
Atualização # 2: Compreendendo a saída do rastreamento JSSE
O keystore e os truststores usados pela JVM são geralmente listados no início, algo como o seguinte:
Se o armazenamento confiável errado for usado, será necessário reimportar o certificado do servidor para o correto ou reconfigurar o servidor para usar o listado (não recomendado se você tiver várias JVMs e todas elas forem usadas para diferentes necessidades).
Se você deseja verificar se a lista de certificados confiáveis contém os certificados necessários, existe uma seção para o mesmo, que começa como:
Você precisará procurar se a autoridade de certificação do servidor é um assunto.
O processo de handshake terá algumas entradas salientes (você precisará conhecer o SSL para entendê-las em detalhes, mas, para fins de depuração do problema atual, será suficiente saber que um handshake_failure geralmente é relatado no ServerHello.
1. ClientHello
Uma série de entradas será relatada quando a conexão estiver sendo inicializada. A primeira mensagem enviada pelo cliente em uma configuração de conexão SSL / TLS é a mensagem ClientHello, geralmente relatada nos logs como:
Observe os conjuntos de criptografia usados. Este pode ter que concordar com a entrada em seu arquivo merchant.properties, para a mesma convenção pode ser empregado por biblioteca do banco. Se a convenção usada for diferente, não haverá motivo de preocupação, pois o ServerHello indicará isso, se o conjunto de criptografia for incompatível.
2. ServerHello
O servidor responde com um ServerHello, que indicará se a configuração da conexão pode continuar. As entradas nos logs geralmente são do seguinte tipo:
Observe o conjunto de cifras que ele escolheu; esse é o melhor pacote disponível para o servidor e o cliente. Normalmente, o conjunto de criptografia não é especificado se houver um erro. O certificado do servidor (e opcionalmente toda a cadeia) é enviado pelo servidor e pode ser encontrado nas entradas como:
Se a verificação do certificado for bem-sucedida, você encontrará uma entrada semelhante a:
Uma das etapas acima não teria êxito, resultando no handshake_failure, pois o handshake normalmente está completo nesse estágio (na verdade não, mas os estágios subsequentes do handshake normalmente não causam falha no handshake). Você precisará descobrir qual etapa falhou e postar a mensagem apropriada como uma atualização para a pergunta (a menos que você já tenha entendido a mensagem e saiba o que fazer para resolvê-la).
fonte
keytool -list -v -keystore $JAVA_HOME/jre/lib/security/cacerts
comando para imprimir o conteúdo. Em seguida, verifique se os certificados em cacerts correspondem à CA do certificado do banco.changeit
. A menos que tenha sido alterado.A instalação da força ilimitada do Java Cryptography Extension (JCE) ( para JDK7 | for JDK8 ) pode corrigir esse erro. Descompacte o arquivo e siga o leia-me para instalá-lo.
fonte
A falha do handshake pode ser uma implementação de protocolo TLSv1 com erros.
No nosso caso, isso ajudou no java 7:
A jvm negociará nesta ordem. Os servidores com a atualização mais recente farão o 1.2, os de buggy descerão para a v1 e isso funciona com a v1 semelhante no java 7.
fonte
Isso também pode acontecer quando o cliente precisa apresentar um certificado. Depois que o servidor lista a cadeia de certificados, pode acontecer o seguinte:
3. Solicitação de certificado O servidor emitirá uma solicitação de certificado do cliente. A solicitação listará todos os certificados que o servidor aceita.
4. Cadeia de Certificados de Clientes Este é o certificado que o cliente está enviando para o servidor.
Se não houver um certificado na cadeia e o servidor exigir um, você receberá o erro de handshake aqui. Uma causa provável é que o caminho para o seu certificado não foi encontrado.
5. Verificação de certificado O cliente solicita ao servidor que verifique o certificado
Esta etapa acontecerá apenas se você estiver enviando um certificado.
6. Concluído O servidor responderá com uma resposta de verificação
fonte
Não acho que isso resolva o problema para o primeiro interlocutor, mas para os googlers que vêm aqui em busca de respostas:
Na atualização 51, o java 1.8 proíbe cifras [1] RC4 por padrão, como podemos ver na página Notas da versão:
Se o seu servidor tiver uma forte preferência por essa cifra (ou usar apenas essa cifra), isso poderá ativar um
handshake_failure
java.Você pode testar a conexão com o servidor ativando as cifras RC4 (primeiro, tente sem
enabled
argumento para ver se dispara a ehandshake_failure
, em seguida, definaenabled
:1 - https://www.java.com/en/download/faq/release_changes.xml
fonte
Eu tenho esse erro enquanto tentava usar o JDK 1.7. Quando atualizei meu JDK para jdk1.8.0_66, tudo começou a funcionar bem.
Portanto, a solução mais simples para esse problema pode ser: atualize seu JDK e ele poderá começar a funcionar bem.
fonte
No meu caso, cert é importado, o erro permanece, resolvido isso adicionando
System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,SSLv3");
antes de conectarfonte
Supondo que você esteja usando os protocolos SSL / TLS adequados, configurando seu
keyStore
e corretamentetrustStore
e confirmando que não existem problemas com os próprios certificados, pode ser necessário reforçar seus algoritmos de segurança .Conforme mencionado na resposta do Vineet , um possível motivo para você receber esse erro é o uso de conjuntos de códigos incompatíveis. Atualizando my
local_policy
eUS_export_policy
jars nasecurity
pasta do meu JDK com os fornecidos na Java Cryptography Extension (JCE) , consegui concluir o handshake com êxito.fonte
Hoje, encontro o mesmo problema com o cliente OkHttp para obter um URL baseado em https. Foi causado pela incompatibilidade da versão do protocolo Https e do método Cipher entre o servidor e o cliente .
1) verifique o site https versão do protocolo e método de cifra.openssl>s_client -connect your_website.com:443 -showcerts
Você obterá muitas informações detalhadas, as principais informações estão listadas a seguir:
2) configure seu cliente http, por exemplo, no caso do cliente OkHttp :Isso vai conseguir o que queremos.
fonte
Encontrei um servidor HTTPS que falhou dessa maneira se meu processo do cliente Java foi configurado com
A conexão falhou
handshake_failure
após aServerHello
conclusão com êxito, mas antes do início do fluxo de dados.Não havia uma mensagem de erro clara que identificasse o problema, o erro parecia
Eu isolei o problema tentando com e sem a
-Djsse.enableSNIExtension=false
opção " "fonte
O meu foi um
TLS
erro de versão incompatível.Anteriormente,
TLSv1
eu mudeiTLSV1.2
isso resolveu o meu problema.fonte
Estou usando o cliente http com.google.api. Quando me comunico com um site interno da empresa, recebi esse problema ao usar por engano https, em vez de http.
fonte
Eu tive uma questão semelhante; a atualização para o Apache HTTPClient 4.5.3 o corrigiu.
fonte
Ugg! Acabou sendo simplesmente um problema de versão do Java para mim. Eu recebi o erro de aperto de mão usando o JRE 1.6 e tudo funcionou perfeitamente usando o JRE 1.8.0_144.
fonte
Isenção de responsabilidade: não sei se a resposta será útil para muitas pessoas, apenas compartilhando porque pode.
Eu estava recebendo esse erro ao usar o Parasoft SOATest para enviar solicitação XML (SOAP).
O problema foi que eu selecionei o alias errado no menu suspenso depois de adicionar o certificado e autenticá-lo.
fonte
No meu caso, o site apenas pode usar o TLSv1.2. e eu uso o apache httpclient 4.5.6, eu uso esse código e instalo o jce para resolver isso (JDK1.7):
jce
jdk7 http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
jdk 8 http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
código:
fonte
Para solucionar problemas da perspectiva do desenvolvedor (item 1) e do administrador do sistema (itens 2 e 3):
-Djavax.net.debug=ssl:handshake:verbose
.sudo apt install ssldump
ou compile a partir da fonte seguindo este link se você observarUnknown value
na cifra quando executar a etapa abaixo.sudo ssldump -k <your-private-key> -i <your-network-interface>
Exemplo de aperto de mão do log ssldump:
Exemplo de handshake bem-sucedido do log ssldump
Exemplo de log Java não funcionando
fonte
No meu caso, tive um problema com a versão 1.1. Eu estava reproduzindo o problema facilmente com curl. O servidor não suporta versões inferiores ao TLS1.2.
Este problema de handshake recebido:
Com a versão 1.2, estava funcionando bem:
O servidor estava executando um Weblogic e a inclusão desse argumento no setEnvDomain.sh fez com que ele funcionasse com o TLSv1.1:
fonte
Este problema está ocorrendo devido à versão java. Eu estava usando o JDK 1.8.0.231 e recebendo esse erro. Eu degradei minha versão java de 1.8.0.231 para 1.8.0.171, agora está funcionando bem.
fonte