午后阳光——纯粹原创空间

转载请邮件联系,谢绝盈利机构转载 音乐教育了我们...

  DonewsBlog  |  Donews首页  |  Donews社区  |  Donews邮箱  |  我的首页  |  联系作者  |  聚合   |  登录
  9篇文章 :: 0篇收藏:: 3篇评论:: 0个Trackbacks

公告


qq:828345
MSN:
tomqq2020@hotmail.com
职业生涯:
从事网络安全设备的开发,IDS,sslvpn,数据库网络审计,漏洞研究。 精通网站脚本语言以及web安全;精通wap,phs开发;主要使用语言为c/c++,java,主要开发平台为linux。
2004年毕业于四川大学计算机应用专业,硕士学历。毕业后进入某研究所从事安全设备研发;目前在某外企从事ssl-vpn的研发。

文章

收藏

相册

我得好朋友

存档


正在读取评论……


java使用HttpsUrlConnection下载一个远程文件时,常规的方法会出现不信任证书的异常,解决的方法就是:使用自信认管理器,示例如下:

Java中忽略對建立SSL連線之certificate的檢查

 

建立SSL連線時,伺服器會提供一份電子憑證(certificate),以供用戶端程式在連線時用以編解與伺服器之間的訊息交換。正常的情況下,在建立連線之際,用戶端程式收到伺服器提供的ceritificate,會向這張ceritifccate的憑證授權單位(CA)要求檢驗此張憑證的有效性。


有許多網站,尤其是還在測試中的網站,因為向憑證授權單位購買憑證是需要花錢的,所以都會自行利用一些簽證的工具,自行產生憑證,一般來說,就被稱為是 self-signedcertificate。當我們透過像IE這樣子的瀏覽器來檢視網址為https://開頭的網站時,倘若看到下述的視窗:



 

通常都是遇上self signed的網站。瀏覽器處理這種情況很簡單,因為它可以詢問使用者是否願意接受,再進行下一步的處理。但是使用Java來連線此類的網站時,事情就比較複雜。倘若我們寫下下述的程式碼:




import java.io.*;


import java.net.*;


 


public class TestCert


{


      public static void main(String argv[])


      {


             try


             {


                   String _url = "https://www.cs.nthu.edu.tw/";


                   URL url = new URL(_url);


                   URLConnection uc = url.openConnection();


                   InputStream is = uc.getInputStream();


                   InputStreamReader isr = new InputStreamReader(is);


                   BufferedReader br = new BufferedReader(isr);


                   String s = br.readLine();


                   System.out.println(s);


                   br.close();


                   isr.close();


             }


             catch(Exception e)


             {


                   e.printStackTrace();


             }


      }


}


這段程式碼基本上就是連接到一個https://的網站,但由於這個網站的憑證是self signed的,所以發生了下述的錯誤:




javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException:


PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderExce


ption: unable to find valid certification path to requested target


        at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:150)


        at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1


518)


這便是JavaSSL socket實作在收到伺服器回傳的憑證時,由於無法認證該憑證,而引發的錯誤。有一個解決的方法,便是把這個憑證加到你Java執行環境中儲存信任憑證的地方,不過這不是本篇blog的主旨,本篇的主旨在於如何忽略檢查,方法如下:


 




import javax.net.ssl.*;


 


TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager()


{


        public java.security.cert.X509Certificate[] getAcceptedIssuers()


        {


                return null;


        }


        public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)


        {


        }


 


        public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)


        {


        }


}};


SSLContext sc = SSLContext.getInstance("SSL");


sc.init(null, trustAllCerts, new java.security.SecureRandom());


HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());


基本上,就是為目前SSLSocketFactory設定一個自訂的TrustManager,並且在TrustManager該有的介面中,pass所有的檢查。如此一來,便可以忽略掉上述所提到的錯誤。


使用上述的方式,必須小心整個application是否會連線到不在預期中的網站,因為這樣子的寫法,等於是開放完全不檢查來自所有網站的憑證是否有效。我是偷懶的人,所以不想把憑證加到信任的cert store去,但因為明確的知道憑證的來源網站,所以才使用忽略的方式,倘若你的情況並非如此,就應該審慎的評估。


另外,如果你所收到的憑證,其中的domain name並未和其實際的domain name相符(我有遇到domain nameIP address的情況:p),也會引發憑證的檢查錯誤,解決之道(其實就是忽略之道)如下:




HostnameVerifier hv = new HostnameVerifier()


{


      public boolean verify(String urlHostName, SSLSession session)


      {


             System.out.println("Warning: URL Host: "+urlHostName+" vs. "+session.getPeerHost());


             return true;


      }


};


HttpsURLConnection.setDefaultHostnameVerifier(hv);


java.net.ssl.HttpsURLConnection設定一個自訂的HostnameVerifier,並且在其verify()中回傳檢查成功(true),就可以把對憑證host name的檢查予以忽略。


以上兩種情況,約略是連接至測試用之https網站的主要問題。


 



Trackback: http://tb.donews.net/TrackBack.aspx?PostId=1249454


[点击此处收藏本文]  发表于2008年01月27日 1:35 PM




正在读取评论……

发表评论

大名:
网址:
验证码
评论