[Android] 인증서 문제 - javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException:Trust anchor for certification path not found

incava·2024년 6월 14일
0
post-thumbnail

문제확인

  1. 브라우저,IOS에서는 정상 작동 되지만 Android에서는 인증서 문제로 접속이 안되는 경우
  2. "Trust anchor for certification path not found"에 대한 문제가 뜨는 경우
  3. 기존에는 정상적으로 작동하였지만, 인증서 교체 또는 만료 후 작동이 안되는 경우

문제 원인

javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException:Trust anchor for certification path not found

원인 설명

Https에 관한 도메인을 읽어오면서 웹사이트에 대한 Certificate 인증서에 대한 경로가 없을 때 일어나는 문제다. 여기서 Certificate을 왜 써야하는가에 대한 부분에 이해가 가지 않을 경우, Http와 Https에 대한 차이점을 알아보고 오는 선행 학습이 필요하다.

해결 방법

해결 방법은 크게 2가지가 있다.
이 문제의 주된 원인은 신뢰하지 않는 인증서이기 때문인데, 이에 대한 부분은 아래를 참조하며 인증서를 연결할 수 있도록 수정해야 한다.

[참고사이트]

하지만 서버 인증서가 정상 동작함에도 인증서 다운로드가 안 될 경우, 앱 내에 인증서를 다운 받아 넣으면 가능하다.
아래는 앱 내에 인증서를 받아 해결 하는 방법이다.

  1. 요청한 URL에 대한 웹사이트에 대한 인증서 다운로드
  2. 다운 받은 인증서를 앱에 저장
  3. HttpConnection을 통한 연결 시 인증서를 추가
    총 3단계를 통해 해당 부분을 해결 할 수 있다.

하지만 이 부분은 인증서 만료 시, 업데이트를 해줘야 하기 때문에 권장하지 않는다.
그럼에도 대체 할 수 있는 임시 방편으로 작용할 수 있으니 적어 본다.

인증서 다운로드

크롬 또는 브라우저에 해당 URL을 접속해 들어간 후,11시 방향의 버튼을 누르고 아래 사진 대로 눌러 인증서를 다운 받아 준다.

인증서를 받게 되면 .cer이라는 확장자 파일을 얻게 되는데 이 파일을 앱 내로 넣어줘야 한다.

앱 소스 구현

이 파일을 /res/raw파일에 넣어준 후, 불러와 연결해주면 되는데 이것을 HttpsURLConnection에서 구현해보자.

        /**
         * 2. HttpURLConnection을 통해 web의 데이터를 가져온다.
         * */
        try {
            Certificate ca;
            InputStream caInput;
            CertificateFactory cf = CertificateFactory.getInstance("X.509");

            caInput = appContext.getResources().openRawResource(R.raw.xxx);//R.raw에서 파일을 가져온다.

            try {
                ca = cf.generateCertificate(caInput);
                System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
            } finally {
                caInput.close();
            }

            // Create a KeyStore containing our trusted CAs
            String keyStoreType = KeyStore.getDefaultType();
            KeyStore keyStore = KeyStore.getInstance(keyStoreType);
            keyStore.load(null, null);
            keyStore.setCertificateEntry("ca", ca);

            // Create a TrustManager that trusts the CAs in our KeyStore
            String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
            tmf.init(keyStore);

            // Create an SSLContext that uses our TrustManager
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, tmf.getTrustManagers(), null);

            URL url = new URL(_url);
            urlConn = (HttpsURLConnection) url.openConnection();
            urlConn.setSSLSocketFactory(sslContext.getSocketFactory()); // ssl을 connection에 저장 

코틀린과 Retrofit을 이용해 만드는 방법도 있는데,아래 링크에서 참고하면 될 듯하다.
참고 사이트

profile
근거있는 코딩하고 싶은 개발자

0개의 댓글

관련 채용 정보