[Java] Apache Commons HttpClient·Î SSL Åë½ÅÇϱâ
* apache httpclient 4.4 ÀÌ»ó ¹öÀü
import org.apache.http.impl.client.HttpClientBuilder; |
* apache httpclient 4.3 ÀÌÇÏ ¹öÀü
import javax.net.ssl.SSLContext; |
===========================================================================================
Ãâó : http://comphy.iptime.org/user/wordpress/?p=81
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 Åë½ÅÀº ¾Æ·¡¿Í °°´Ù.
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: 200 Response Status Line: HTTP/1.1 200 OK Response 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: 404 Response Status Line: HTTP/1.1 404 Not Found Response 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 found at 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 found at 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 cacerts Enter keystore password: changeit Keystore type: jks Keystore provider: SUN Your keystore contains 52 entries Alias name: verisignclass3g2ca Creation date: Jun 16, 2004 Entry type: trustedCertEntry Owner: OU=VeriSign Trust Network, OU="(c) 1998 VeriSign, Inc. - For authorized use only", OU=Class 3 Public Primary Certification Authority - G2, O="VeriSign, Inc.", C=US Issuer: OU=VeriSign Trust Network, OU="(c) 1998 VeriSign, Inc. - For authorized use only", OU=Class 3 Public Primary Certification Authority - G2, O="VeriSign, Inc.", C=US Serial number: 7dd9fe07cfa81eb7107967fba78934c6 Valid from: Mon May 18 09:00:00 KST 1998 until: Wed Aug 02 08:59:59 KST 2028 Certificate fingerprints: MD5: A2:33:9B:4C:74:78:73:D4:6C:E7:C1:F3:8D:CB:5C:E9 SHA1: 85:37:1C:A6:E5:50:14:3D:CE:28:03:47:1B:DE:3A:09:E8:F8:77:0F ******************************************* ******************************************* Alias name: entrustclientca Creation date: Jan 10, 2003 Entry type: trustedCertEntry Owner: CN=Entrust.net Client Certification Authority, OU=(c) 1999 Entrust.net Limited, OU=www.entrust.net/Client_CA_Info/CPS incorp. by ref. limits liab., O=Entrust.net, C=US Issuer: CN=Entrust.net Client Certification Authority, OU=(c) 1999 Entrust.net Limited, OU=www.entrust.net/Client_CA_Info/CPS incorp. by ref. limits liab., O=Entrust.net, C=US Serial number: 380391ee Valid from: Wed Oct 13 04:24:30 KST 1999 until: Sun Oct 13 04:54:30 KST 2019 Certificate fingerprints: MD5: 0C:41:2F:13:5B:A0:54:F5:96:66:2D:7E:CD:0E:03:F4 SHA1: 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 tradesignca Enter keystore password: changeit Owner: CN=TradeSignCA, OU=AccreditedCA, O=TradeSign, C=KR Issuer: CN=KISA RootCA 1, OU=Korea Certification Authority Central, O=KISA, C=KR Serial number: 2764 Valid from: Tue Nov 15 11:14:59 KST 2005 until: Sun Nov 15 11:14:59 KST 2015 Certificate 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:BE Trust this certificate? [no]: y Certificate was added to keystore |
ÀÌ·¸°Ô ¼¹ö CA ÀÎÁõ¼°¡ ½Å·ÚÇÏ´Â ÀÎÁõ¼·Î µî·ÏÀÌ µÇ¸é, ÀÏ¹Ý HTTP Åë½Å°ú °°ÀÌ URLÀÌ https://ÀÎ ÁÖ¼Ò·Î SSL Åë½ÅÀ» Á¤»óÀûÀ¸·Î ÇÒ ¼ö ÀÖ´Ù. Å°½ºÅä¾î ÆÄÀÏ¿¡¼ ÀÎÁõ¼¸¦ Á¦°ÅÇÏ´Â ¹æ¹ýÀº ¾Æ·¡¿Í °°´Ù.
C:\jdk1.4.2\jre\lib\security>keytool -delete -keystore cacerts -alias tradesignca Enter keystore password: changeit |
¾Æ·¡Ã³·³ ¼¹ö ½ÎÀÌÆ® ÀÎÁõ¼¸¦ ¹Ù·Î µî·ÏÇÒ ¼öµµ ÀÖ´Ù. ±×·¯³ª ½ÎÀÌÆ® ÀÎÁõ¼´Â º¸Åë Trusted CA ÀÎÁõ¼º¸´Ù À¯È¿±â°£ÀÌ Âª¾Æ ¸Å¹ø °»½ÅÀ» ÇØÁà¾ß ÇÒ °ÍÀÌ´Ù.
C:\jdk1.4.2\jre\lib\security>keytool -import -keystore cacerts -file c:\certs\www.java2go.net.cer -alias mykey Enter keystore password: changeit Owner: CN=www.java2go.net, OU=KTNET, OU=AccreditedCA, O=TradeSign, C=KR Issuer: CN=TradeSignCA, OU=AccreditedCA, O=TradeSign, C=KR Serial number: 596e9cf0 Valid from: Tue May 12 13:37:20 KST 2009 until: Wed May 12 14:07:20 KST 2010 Certificate 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:2D Trust this certificate? [no]: y Certificate 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 |