javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException:Trust anchor for certification path not found
Https에 관한 도메인을 읽어오면서 웹사이트에 대한 Certificate 인증서에 대한 경로가 없을 때 일어나는 문제다. 여기서 Certificate을 왜 써야하는가에 대한 부분에 이해가 가지 않을 경우, Http와 Https에 대한 차이점을 알아보고 오는 선행 학습이 필요하다.
해결 방법은 크게 2가지가 있다.
이 문제의 주된 원인은 신뢰하지 않는 인증서이기 때문인데, 이에 대한 부분은 아래를 참조하며 인증서를 연결할 수 있도록 수정해야 한다.
하지만 서버 인증서가 정상 동작함에도 인증서 다운로드가 안 될 경우, 앱 내에 인증서를 다운 받아 넣으면 가능하다.
아래는 앱 내에 인증서를 받아 해결 하는 방법이다.
하지만 이 부분은 인증서 만료 시, 업데이트를 해줘야 하기 때문에 권장하지 않는다.
그럼에도 대체 할 수 있는 임시 방편으로 작용할 수 있으니 적어 본다.
크롬 또는 브라우저에 해당 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을 이용해 만드는 방법도 있는데,아래 링크에서 참고하면 될 듯하다.
참고 사이트