Java 의 SSLHandshakeException 문제 해결
No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
증상
java 에서 HTTPS 로 remote 사이트에 연결시 다음과 같은 Exception 이 발생
javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate)
원인
서버/클라이언트간 사용하려는 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();
}
}
JAVA
컴파일
javac Hc.java
CODE실행
SSL 버전 확인을 위해 -Djavax.net.ssl.debug=all 추가 필요
java -Djavax.net.debug=all Hc https://example.com
CODE
SSLHandshakeException: Received fatal alert: handshake_failure
증상
javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1959)
at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1077)
at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
at sun.security.ssl.AppOutputStream.write(AppOutputStream.java:122)
원인
SSL/TLS 버전이 맞지 않음. 주로 서버가 강력한 암호화를 사용하지만(TLS 1.2) client 의 TLS 가 버전이 낮아서 오래된 알고리즘을 사용할 경우 발생함.
다음 명령어로 서버가 사용하는 TLS 버전과 알고리즘을 확인할 수 있음.
$ openssl s_client -connect myserver.com:443
CODE
해결
- Client 의 TLS 버전을 올리고 (JDK 업그레이드등) 강력한 알고리즘을 사용하도록 수정
같이 보기