-
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() 메소드를 실행하면 됩니다.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475import 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 certificatefinal 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 chainsTrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {public java.security.cert.X509Certificate[] getAcceptedIssuers() {return new java.security.cert.X509Certificate[] {};}@Overridepublic void checkClientTrusted(X509Certificate[] chain,String authType) throws CertificateException {}@Overridepublic void checkServerTrusted(X509Certificate[] chain,String authType) throws CertificateException {}}};// Install the all-trusting trust managertry {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
'Mhwan's Develope > Android' 카테고리의 다른 글
[Tip] Android Universal Image Loader 라이브러리 사용팁 (갤러리에서 선택한 이미지 보여주기) (0) 2016.11.02 [Tip] 안드로이드 사용자 주소록 리스트 가져오기 (0) 2016.10.27 [Tip] 안드로이드 디바이스 화면 사이즈 알아내기 (0) 2016.10.27 [Tip] 안드로이드 dp<->px 변환 (0) 2016.10.27 [Tip] 레이아웃 페이드인 애니메이션 (Fade in Layout) (0) 2016.10.25