ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Android Note] javax.net.ssl.SSLHandshakeException 인증서오류
    Mhwan's Develope/Android 2020. 3. 8. 22:49

    Android로 앱을 개발하거나 Java로 프로그램을 개발할때 가끔 겪게 되는 인증서가 필요할때 생기는 오류입니다.

    저는 학교 앱을 만들면서 학교 서버에서 데이터를 받아 파싱하는데 이 오류를 겪었는데, 제게 생소한 오류여서 이번기회에 공부하여 문제를 해결한 뒤 적습니다

    # Error Log

    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path validation failed: java.security.cert.CertPathValidatorException: validity check failed

    이 오류는 페이지에 접속하다보면 간혹 관공서나 학교 등 인증서를 요구하는 웹 페이지에 접속할때 발생하는 오류 입니다.

     

    # How to fix?

    대표적으로 두가지의 해결방법이 있다고 합니다.

    1. 과거 오라클에서 배포한 인증서를 얻는 코드(InstallCert.java)를 이용해서 해결하는 방법 (<-저는 이방법을 사용하지 않아 인터넷에 검색해보는 것을 추천합니다.)

    2. 자바 코드로 SSL을 무시하고 우회하여 강제 접속을 하게 만드는 방법이 있습니다. (안드로이드같은 환경에서도 1번과 같은 방법으로 해결을 할 수 있지만 OS안에 해당 경로에 접속하기 힘든 어려움이 존재.. ) (저는 이방법으로 해결하였으므로 이 내용을 기술합니다.)

    아래의 코드를 HttpUrlConnection의 connection 이전에 postHttps() 메소드를 실행하면 됩니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    import java.io.IOException;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.security.cert.CertificateException;
    import java.security.cert.X509Certificate;
     
    import javax.net.ssl.HostnameVerifier;
    import javax.net.ssl.HttpsURLConnection;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.SSLSession;
    import javax.net.ssl.TrustManager;
    import javax.net.ssl.X509TrustManager;
     
    public class SSLCertificateUtil {
        // always verify the host - dont check for certificate
        final HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
            public boolean verify(String hostname, SSLSession session) {
                return true;
            }
        };
     
        /**
         * Trust every server - don't check for any certificate
         */
        private void trustAllHosts() {
            // Create a trust manager that does not validate certificate chains
            TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
                public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                    return new java.security.cert.X509Certificate[] {};
                }
     
                @Override
                public void checkClientTrusted(X509Certificate[] chain,
                                               String authType) throws CertificateException {
                }
     
                @Override
                public void checkServerTrusted(X509Certificate[] chain,
                                               String authType) throws CertificateException {
                }
            }};
     
            // Install the all-trusting trust manager
            try {
                SSLContext sc = SSLContext.getInstance("TLS");
                sc.init(null, trustAllCerts, new java.security.SecureRandom());
                HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
     
        public HttpsURLConnection postHttps(String url, int connTimeout, int readTimeout) {
            trustAllHosts();
     
            HttpsURLConnection https = null;
            try {
                https = (HttpsURLConnection) new URL(url).openConnection();
                https.setHostnameVerifier(DO_NOT_VERIFY);
                https.setConnectTimeout(connTimeout);
                https.setReadTimeout(readTimeout);
            }
            catch (MalformedURLException e) {
                e.printStackTrace();
                return null;
            }
            catch (IOException e) {
                e.printStackTrace();
                return null;
            }
            return https;
        }
    }
     
    cs

     

    저 같은 경우 원래 이 에러가 나지 않다가 나게된 경우여서 인증서가 필요할 때와 필요하지 않아도 되는 때 가 있습니다.

    그래서 일반적인 방법으로 연결을 시도하고 만약 에러가 날 경우 catch문에서 SSLHandshakeException이 발생할 경우 위 코드를 실행하고 재 접속을 하는 방법을 사용했습니다.

     

    이게 최선의 방법인지는 아직 모르겠으나 현재까지로는 아무 문제가 없더군요 혹시 아시는 분이 있다면 댓글 남겨주세요.

     

    출처 : https://ram2ram2.tistory.com/16, https://twinw.tistory.com/46

    댓글

Designed by Mhwan.