Commons HttpClient로 SSL 통신하기 ::
[출처] http://www.java2go.net/blog/197?TSSESSION=1202a1a23fa67bae15ce3ab15a5a0cea
Apache Commons HttpClient는 JDK 1.4부터 등장한 Java Secure Socket Extension (JSSE)를 기반으로 SSL (또는 TLS) 상의 HTTP (HTTP/S) 통신에 대한 지원을 제공한다. Commons HttpClient를 이용한 HTTP/S 통신 방법을 살펴보자.
1. Commons HttpClient 사용하기
일반적으로 Commons HttpClient의 HTTP 통신은 아래와 같다.
정상적인 경우 결과는 아래와 같다.
실패한 경우 결과는 아래와 같다.
2. SSL 통신과 Trusted CA 인증서 등록하기
JSSE가 올바르게 설치되었다면, 기본적으로 HTTP/S 통신도 일반 HTTP 통신과 같이 위와 같은 코드를 그대로 사용할 수 있다. 단, 이 경우에 서버 싸이트 인증서가 클라이언트쪽에 신뢰하는 인증서로서 인식될 수 있어야 한다. 그렇지 않으면 아래와 같은 SSL handshake 오류가 발생한다.
JDK에 의해 제공되어지는 Java Standard Trust Keystore는 ${JAVA_HOME}/jre/lib/security/cacerts에 위치한다. 이 cacerts 키스토어 파일에 대상 서버의 SSL 싸이트 인증서를 발행한 기관의 CA 인증서가 신뢰하는 인증서로 등록되어 있어야 한다. 다음과 같이 keytool.exe를 사용하여 키스토어에 등록된 신뢰하는 인증서 목록을 조회할 수 있다.
다음과 같은 방법으로 키스토어 파일에 Trusted CA 인증서를 추가로 등록할 수 있다. CA 인증서는 웹브라우저에서 열쇠모양의 아이콘을 누르면 해당 싸이트 인증서를 볼 수 있고, 거기에서 인증서를 복사할 수 있다. 아래 예시는 Trusted CA 인증서를 ${JAVA_HOME}\jre\lib\secutiry\cacerts에 등록을 하는 방법이다.
이렇게 서버 CA 인증서가 신뢰하는 인증서로 등록이 되면, 일반 HTTP 통신과 같이 URL이 https://인 주소로 SSL 통신을 정상적으로 할 수 있다. 키스토어 파일에서 인증서를 제거하는 방법은 아래와 같다.
아래처럼 서버 싸이트 인증서를 바로 등록할 수도 있다. 그러나 싸이트 인증서는 보통 Trusted CA 인증서보다 유효기간이 짧아 매번 갱신을 해줘야 할 것이다.
3. Commons HttpClient의 SSL 커스터마이징
기본적인 사용법 이외에 자기서명(self-signed)되었거나 또는 신뢰되지 않은(untrusted) SSL 인증서를 사용하는 경우처럼 SSL 통신을 커스터마이징할 필요가 있을 수 있다.
기본 커스터마이징 방법은 org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory을 구현해서 org.apache.commons.httpclient.protocol.Protocol를 생성하여 등록해주면 된다. 다음과 같은 코드 한 줄을 추가해 주면 된다. 자세한 내용은 이곳을 참조한다.
Commons HttpClient의 contribution 패키지에서 사용할 수 있는 EasySSLProtocolSocketFactory를 사용하면 신뢰되지 않은 자기서명(self-signed)된 인증서를 가진 서버와도 바로 SSL 통신을 할 수 있다. 즉, cacerts 키스토어에 서버 인증서를 별도로 등록할 필요가 없다. 다음과 같이 사용할 수 있다.
호출 로그
참조: http://hc.apache.org/httpclient-3.x/sslguide.html
1. Commons HttpClient 사용하기
일반적으로 Commons HttpClient의 HTTP 통신은 아래와 같다.
import org.apache.commons.httpclient.HttpClient;import org.apache.commons.httpclient.HttpStatus;import org.apache.commons.httpclient.methods.GetMethod;// import org.apache.commons.httpclient.methods.PostMethod;public class HttpClientSample { public static void main(String[] args) { HttpClient httpclient = new HttpClient(); GetMethod httpget = new GetMethod("http://www.java2go.net/"); // PostMethod httppost = new // PostMethod("https://www.java2go.net/nopage.html"); try { int statusCode = httpclient.executeMethod(httpget); System.out.println("Response Status Code: " + statusCode); System.out.println("Response Status Line: " + httpget.getStatusLine()); System.out.println("Response Body: \n" + httpget.getResponseBodyAsString()); if (statusCode == HttpStatus.SC_OK) { // if (statusCode >= 200 && statusCode < 300) { System.out.println("Success!"); } else { System.out.println("Fail!"); } } catch (Exception e) { e.printStackTrace(); } finally { httpget.releaseConnection(); } }} |
정상적인 경우 결과는 아래와 같다.
Response Status Code: 200Response Status Line: HTTP/1.1 200 OKResponse Body: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><title>Java2go.net</title><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />... 생략 ...</body></html>Success! |
실패한 경우 결과는 아래와 같다.
Response Status Code: 404Response Status Line: HTTP/1.1 404 Not FoundResponse Body: <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"><HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD><BODY><H1>Not Found</H1>The requested URL /nopage.html was not found on this server.<P><HR><ADDRESS>Apache/1.3.37p3 Server at java2go.net Port 80</ADDRESS></BODY></HTML>Fail! |
2. SSL 통신과 Trusted CA 인증서 등록하기
JSSE가 올바르게 설치되었다면, 기본적으로 HTTP/S 통신도 일반 HTTP 통신과 같이 위와 같은 코드를 그대로 사용할 수 있다. 단, 이 경우에 서버 싸이트 인증서가 클라이언트쪽에 신뢰하는 인증서로서 인식될 수 있어야 한다. 그렇지 않으면 아래와 같은 SSL handshake 오류가 발생한다.
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate foundat com.sun.net.ssl.internal.ssl.BaseSSLSocketImpl.a(DashoA12275)at com.sun.net.ssl.internal.ssl.SSLSocketImpl.a(DashoA12275)at com.sun.net.ssl.internal.ssl.SSLSocketImpl.a(DashoA12275)at com.sun.net.ssl.internal.ssl.SunJSSE_az.a(DashoA12275)at com.sun.net.ssl.internal.ssl.SunJSSE_az.a(DashoA12275)at com.sun.net.ssl.internal.ssl.SunJSSE_ax.a(DashoA12275)at com.sun.net.ssl.internal.ssl.SSLSocketImpl.a(DashoA12275)at com.sun.net.ssl.internal.ssl.SSLSocketImpl.j(DashoA12275)at com.sun.net.ssl.internal.ssl.SSLSocketImpl.a(DashoA12275)at com.sun.net.ssl.internal.ssl.AppOutputStream.write(DashoA12275)... 생략 ...Caused by: sun.security.validator.ValidatorException: No trusted certificate foundat sun.security.validator.SimpleValidator.buildTrustedChain(SimpleValidator.java:304)at sun.security.validator.SimpleValidator.engineValidate(SimpleValidator.java:107)at sun.security.validator.Validator.validate(Validator.java:202)at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(DashoA12275)at com.sun.net.ssl.internal.ssl.JsseX509TrustManager.checkServerTrusted(DashoA12275)... 17 more |
JDK에 의해 제공되어지는 Java Standard Trust Keystore는 ${JAVA_HOME}/jre/lib/security/cacerts에 위치한다. 이 cacerts 키스토어 파일에 대상 서버의 SSL 싸이트 인증서를 발행한 기관의 CA 인증서가 신뢰하는 인증서로 등록되어 있어야 한다. 다음과 같이 keytool.exe를 사용하여 키스토어에 등록된 신뢰하는 인증서 목록을 조회할 수 있다.
C:\jdk1.4.2\jre\lib\security>keytool -list -v -keystore cacertsEnter keystore password: changeitKeystore type: jksKeystore provider: SUNYour keystore contains 52 entriesAlias name: verisignclass3g2caCreation date: Jun 16, 2004Entry type: trustedCertEntryOwner: OU=VeriSign Trust Network, OU="(c) 1998 VeriSign, Inc. - For authorizeduse only", OU=Class 3 Public Primary Certification Authority - G2, O="VeriSign,Inc.", C=USIssuer: OU=VeriSign Trust Network, OU="(c) 1998 VeriSign, Inc. - For authorizeduse only", OU=Class 3 Public Primary Certification Authority - G2, O="VeriSign,Inc.", C=USSerial number: 7dd9fe07cfa81eb7107967fba78934c6Valid from: Mon May 18 09:00:00 KST 1998 until: Wed Aug 02 08:59:59 KST 2028Certificate fingerprints:MD5: A2:33:9B:4C:74:78:73:D4:6C:E7:C1:F3:8D:CB:5C:E9SHA1: 85:37:1C:A6:E5:50:14:3D:CE:28:03:47:1B:DE:3A:09:E8:F8:77:0F**************************************************************************************Alias name: entrustclientcaCreation date: Jan 10, 2003Entry type: trustedCertEntryOwner: CN=Entrust.net Client Certification Authority, OU=(c) 1999 Entrust.netLimited, OU=www.entrust.net/Client_CA_Info/CPS incorp. by ref. limits liab.,O=Entrust.net, C=USIssuer: CN=Entrust.net Client Certification Authority, OU=(c) 1999 Entrust.netLimited, OU=www.entrust.net/Client_CA_Info/CPS incorp. by ref. limits liab.,O=Entrust.net, C=USSerial number: 380391eeValid from: Wed Oct 13 04:24:30 KST 1999 until: Sun Oct 13 04:54:30 KST 2019Certificate fingerprints:MD5: 0C:41:2F:13:5B:A0:54:F5:96:66:2D:7E:CD:0E:03:F4SHA1: DA:79:C1:71:11:50:C2:34:39:AA:2B:0B:0C:62:FD:55:B2:F9:F5:80... 생략 ... |
다음과 같은 방법으로 키스토어 파일에 Trusted CA 인증서를 추가로 등록할 수 있다. CA 인증서는 웹브라우저에서 열쇠모양의 아이콘을 누르면 해당 싸이트 인증서를 볼 수 있고, 거기에서 인증서를 복사할 수 있다. 아래 예시는 Trusted CA 인증서를 ${JAVA_HOME}\jre\lib\secutiry\cacerts에 등록을 하는 방법이다.
C:\j2sdk1.4.2\jre\lib\security>keytool -import -keystore cacerts -file c:\certs\TradeSignCA.cer -alias tradesigncaEnter keystore password: changeitOwner: CN=TradeSignCA, OU=AccreditedCA, O=TradeSign, C=KRIssuer: CN=KISA RootCA 1, OU=Korea Certification Authority Central, O=KISA, C=KRSerial number: 2764Valid from: Tue Nov 15 11:14:59 KST 2005 until: Sun Nov 15 11:14:59 KST 2015Certificate fingerprints: MD5: C2:E0:27:3D:36:4B:86:29:74:4D:6B:9F:5A:B5:01:26 SHA1: A0:CD:6A:6D:A4:7B:73:15:F5:8A:CB:1F:C6:FD:C2:14:C9:3B:5D:BETrust this certificate? [no]: yCertificate was added to keystore |
이렇게 서버 CA 인증서가 신뢰하는 인증서로 등록이 되면, 일반 HTTP 통신과 같이 URL이 https://인 주소로 SSL 통신을 정상적으로 할 수 있다. 키스토어 파일에서 인증서를 제거하는 방법은 아래와 같다.
C:\jdk1.4.2\jre\lib\security>keytool -delete -keystore cacerts -alias tradesigncaEnter keystore password: changeit |
아래처럼 서버 싸이트 인증서를 바로 등록할 수도 있다. 그러나 싸이트 인증서는 보통 Trusted CA 인증서보다 유효기간이 짧아 매번 갱신을 해줘야 할 것이다.
C:\jdk1.4.2\jre\lib\security>keytool -import -keystore cacerts -filec:\certs\www.java2go.net.cer -alias mykeyEnter keystore password: changeitOwner: CN=www.java2go.net, OU=KTNET, OU=AccreditedCA, O=TradeSign, C=KRIssuer: CN=TradeSignCA, OU=AccreditedCA, O=TradeSign, C=KRSerial number: 596e9cf0Valid from: Tue May 12 13:37:20 KST 2009 until: Wed May 12 14:07:20 KST 2010Certificate fingerprints: MD5: EF:EB:11:66:BD:CC:B1:D4:88:35:AB:25:9F:2F:79:8B SHA1: DC:C4:31:20:46:25:72:68:8B:96:AC:92:EE:F3:8D:15:EF:A7:46:2DTrust this certificate? [no]: yCertificate was added to keystore |
3. Commons HttpClient의 SSL 커스터마이징
기본적인 사용법 이외에 자기서명(self-signed)되었거나 또는 신뢰되지 않은(untrusted) SSL 인증서를 사용하는 경우처럼 SSL 통신을 커스터마이징할 필요가 있을 수 있다.
기본 커스터마이징 방법은 org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory을 구현해서 org.apache.commons.httpclient.protocol.Protocol를 생성하여 등록해주면 된다. 다음과 같은 코드 한 줄을 추가해 주면 된다. 자세한 내용은 이곳을 참조한다.
Protocol.registerProtocol("https", new Protocol("https", new MySSLSocketFactory(), 443)); |
Commons HttpClient의 contribution 패키지에서 사용할 수 있는 EasySSLProtocolSocketFactory를 사용하면 신뢰되지 않은 자기서명(self-signed)된 인증서를 가진 서버와도 바로 SSL 통신을 할 수 있다. 즉, cacerts 키스토어에 서버 인증서를 별도로 등록할 필요가 없다. 다음과 같이 사용할 수 있다.
import org.apache.commons.httpclient.HttpClient;import org.apache.commons.httpclient.HttpStatus;import org.apache.commons.httpclient.contrib.ssl.EasySSLProtocolSocketFactory;import org.apache.commons.httpclient.methods.GetMethod;import org.apache.commons.httpclient.protocol.Protocol;public class HttpClientSample2 { public static void main(String[] args) { HttpClient httpclient = new HttpClient(); GetMethod httpget = new GetMethod("https://www.java2go.net/"); try { Protocol.registerProtocol("https", new Protocol("https", new EasySSLProtocolSocketFactory(), 443)); int statusCode = httpclient.executeMethod(httpget); System.out.println("Response Status Code: " + statusCode); System.out.println("Response Status Line: " + httpget.getStatusLine()); System.out.println("Response Body: \n" + httpget.getResponseBodyAsString()); if (statusCode == HttpStatus.SC_OK) { System.out.println("Success!"); } else { System.out.println("Fail!"); } } catch (Exception e) { e.printStackTrace(); } finally { httpget.releaseConnection(); } }} |
호출 로그
{DEBUG} [2009-06-18 23:29:31,062] <org.apache.commons.httpclient.HttpConnection> () : Open connection to www.java2go.net:443 |
참조: http://hc.apache.org/httpclient-3.x/sslguide.html
'Computer Science' 카테고리의 다른 글
VISUALSVN SERVER // Installing Trac with VisualSVN Server (0) | 2012.01.02 |
---|---|
자바 SSL 사용법 (0) | 2011.12.30 |
[알아봅시다] 망중립성 가이드라인 (0) | 2011.12.25 |
[알아봅시다] 안드로이드 4.0 ICS (0) | 2011.12.21 |
[알아봅시다] 스토리텔링 (0) | 2011.12.21 |