본문 바로가기
안드로이드

HTTPS 통신하기

by 호군 2014. 1. 25.
반응형

안드로이드에서 HTTPS 통신을 할 때, SSL 예외가 발생하는 경우, 아래와 같은 방법을 통해서 예외를 회피 할 수 있다.

이 방법은 모든 URL에 동작하는 방법으로 별도의 인증서 없이 사용하는 방법이다.


URLConnection을 이용한 HTTPS 통신

try {

    HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {

        public boolean verify(String hostname, SSLSession session) {

            return true;

        }

    });


    SSLContext context = SSLContext.getInstance("TLS");

    context.init(null, new X509TrustManager[]{ new X509TrustManager(){

        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}

        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}

        public X509Certificate[] getAcceptedIssuers() {

            return new X509Certificate[0];

        }

    }}, new SecureRandom());


    HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());

    

    URL url = new URL("https://www.example.com");

    URLConnection conn = url.openConnection();

} catch (Exception e) { // should never happen

    e.printStackTrace();

}




HTTPClient를 이용한 HTTPS  통신

try {

    KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());

    trustStore.load(null, null);

    SSLSocketFactory sf = new MySSLSocketFactory(trustStore);

    sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

    HttpParams params = new BasicHttpParams();

    HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);

    HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

    SchemeRegistry registry = new SchemeRegistry();

    registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));

    registry.register(new Scheme("https", sf, 443));

    ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);


    HttpClient httpClient = new DefaultHttpClient(ccm, params);


    HttpGet httpRequest = new HttpGet("https://www.example.com");

    HttpResponse httpResponse = httpClient.execute(httpRequest);

} catch ( KeyStoreException e ) {

    e.printStackTrace();

} catch ( KeyManagementException e ) {

    e.printStackTrace();

} catch ( UnrecoverableKeyException e ) {

    e.printStackTrace();

} catch ( NoSuchAlgorithmException e ) {

    e.printStackTrace();

} catch ( CertificateException e ) {

    e.printStackTrace();

}




public class MySSLSocketFactory extends SSLSocketFactory {

    SSLContext sslContext = SSLContext.getInstance("TLS");


    public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {

        super(truststore);


        TrustManager tm = new X509TrustManager() {

            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { }


            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { }


            public X509Certificate[] getAcceptedIssuers() {

                return null;

            }

        };


        sslContext.init(null, new TrustManager[] { tm }, null);

    }


    public MySSLSocketFactory(SSLContext context) throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {

        super(null);

        sslContext = context;

    }


    @Override

    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {

        return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);

    }


    @Override

    public Socket createSocket() throws IOException {

        return sslContext.getSocketFactory().createSocket();

    }

}



위의 ThreadSafeClientConnectionManager를 이용하여 서버에 여러번 요청을 하다보면 HttpClient.execute()를 수행할 때, 서버에 요청을 하지 못하고 Block되는 경우가 있습니다. 그래서 ThreadSafeClientConnectionManager 대신 SingleClientConnManager를 사용하여 테스트해 본 결과 Block되는 현상이 사라졌습니다. 위의 MySSLSocketFactory 클래스는 여전히 사용됩니다. 기본 SSLSocketFactory를 사용하면 GalaxyS3에는 예외가 발생하는군요. 코드는 아래와 같습니다. 


public class MyHttpClient {

    private final int DEFAULT_TIMEOUT = 5000;

    private ClientConnectionManager mClientConnectionManager;

    private HttpParams mHttpParams;


    private HttpClient mHttpClient;


    private void init() {

        setupHttps();

        mHttpClient = new DefaultHttpClient(mClientConnectionManager, mHttpParams);

        setTimemoutMillis(DEFAULT_TIMEOUT);

    }


    private void setupHttps() {

        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());

        trustStore.load(nullnull);

        SSLSocketFactory sf = new MySSLSocketFactory(trustStore);

        sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        

        HttpParams params = new BasicHttpParams();

        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);

        HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

        mHttpParams = params;

        

        SchemeRegistry registry = new SchemeRegistry();

        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));

        registry.register(new Scheme("https", sf, 443));

        

        mClientConnectionManager = new SingleClientConnManager(params, registry);

    }


    public void setTimeoutMillis(int milliseconds) {

        HttpParams params = mHttpClient.getParams();

        HttpConnectionParams.setConnectionTimeout(params, milliseconds);

        HttpConnectionParams.setSoTimeout(params, milliseconds);

    }

    

}



링크 모음

http://stackoverflow.com/questions/2012497/accepting-a-certificate-for-https-on-android

http://stackoverflow.com/questions/2740975/https-with-self-signed-ssl-certificate-issues-solution-or-better-way

http://blog.daum.net/dna77/15

http://dhjin.egloos.com/2527436


반응형