Java 의 SSLHandshakeException 문제 해결
No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
증상
java 에서 HTTPS 로 remote 사이트에 연결시 다음과 같은 Exception 이 발생
원인
서버/클라이언트간 사용하려는 SSL/TLS 버전이 맞지 않음(TLS 1.2 만 지원하는 서버에 1.0로 hand shaking 요청등)
서버가 TLS 1.2 만 사용하는 경우 JDK 1.8 부터 TLS 1.2 가 기본이므로 예전 JDK 를 사용하는 클라이언트는 위 예외가 발생함.
해결
먼저 사용하는 연결하려는 사이트와 어떤 TLS 버전을 사용하는지 확인하기 위해 다음 코드를 Hc.java 로 저장한다.
import java.io.IOException; import java.net.URL; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import javax.net.ssl.HttpsURLConnection; import javax.security.cert.CertificateException; public class Hc { public static void main(String[] args) throws IOException, CertificateEncodingException, CertificateException { if (args == null || args.length == 0) { System.err.println("url parameter not suppplied. "); System.exit(0); } URL url; url = new URL(args[0]); HttpsURLConnection con = (HttpsURLConnection) url.openConnection(); System.out.println("Response Code : " + con.getResponseCode()); System.out.println("Cipher Suite : " + con.getCipherSuite()); System.out.println("\n"); Certificate[] certs = con.getServerCertificates(); for (Certificate cert : certs) { javax.security.cert.X509Certificate c = javax.security.cert.X509Certificate.getInstance(cert.getEncoded()); System.out.println("\tCert Dn : " + c.getSubjectDN()); System.out.println("\tIssuer Dn : " + c.getIssuerDN()); System.out.println("\n"); } con.disconnect(); } }
컴파일
javac Hc.java
실행
SSL 버전 확인을 위해 -Djavax.net.ssl.debug=all 추가 필요
java -Djavax.net.debug=all Hc https://example.com
SSLHandshakeException: Received fatal alert: handshake_failure
증상
원인
SSL/TLS 버전이 맞지 않음. 주로 서버가 강력한 암호화를 사용하지만(TLS 1.2) client 의 TLS 가 버전이 낮아서 오래된 알고리즘을 사용할 경우 발생함.
다음 명령어로 서버가 사용하는 TLS 버전과 알고리즘을 확인할 수 있음.
$ openssl s_client -connect myserver.com:443
해결
- Client 의 TLS 버전을 올리고 (JDK 업그레이드등) 강력한 알고리즘을 사용하도록 수정
같이 보기