Java Tip 96: 使用 HTTPS 編寫用戶端程式

來源:互聯網
上載者:User
Java Tip 96: 使用 HTTPS 編寫用戶端程式
如何在標準 URL 類中使用 HTTPS 協議

By Matt Towers

摘要
使用 HTTPS(Hypertext Transfer Protocol Secure 安全超文字傳輸通訊協定 (HTTPS))並非你所想的那樣簡單直接。如果你曾經嘗試在 Java 用戶端和 HTTPS 伺服器之間進行安全的通訊,也許會注意到標準的 java.net.URL 類並不支援 HTTPS協議。這篇文章將向你展示,如何使用 JDK 1.2-compatible 虛擬機器或微軟的 JDK 1.1-compatible JView 來克服這些限制。

如果你曾經嘗試在 Java 客戶機和 HTTPS(安全超文字傳輸通訊協定 (HTTPS))伺服器之間進行安全的通訊,也許會注意到標準的 java.net.URL 類並不支援 HTTPS 協議。服務端解決此問題的方法是非常簡單明了的。因為現今幾乎所有的Web伺服器都使用 HTTPS 協議來提供查詢資料的機制。一旦配置好你的伺服器,任何瀏覽器只要簡單地將 URL 地址中的協議指定成 HTTPS ,就能夠在你的伺服器上安全地進行資訊查詢。如果你沒有搭建起 HTTPS 伺服器,則可以在互連網上幾乎所有 HTTPS 網頁中測試你的用戶端代碼。在資料部分給出了一個列表,裡面列出若干可供你進行 HTTPS 通訊測試的伺服器位址。

然而從用戶端的角度來看,在熟悉的 HTTP 後面簡單的加上“S”就能夠安全通訊。這種簡單性充滿了迷惑性。事實上,瀏覽器在後台做了大量的工作,以保證沒有任何人篡改或竊聽你所發送的請求資料。然而 HTTPS 協議用來加密的演算法是 RSA Security 所擁有的專利(這種狀況至少還要持續幾個月)。該密碼編譯演算法得到了瀏覽器製造商的許可,但 Sum Microsystems 公司卻不同意將它綁定到標準的 Java URL 類實現中。這就導致當你建立 URL 對象時,若將協議指定為 HTTPS,就會拋出一個 MalformedURLException 異常。

幸運的是,為瞭解決這個局限,Java規格說明書提供為 URL 類選擇一個代替的流控制代碼的能力。然而當你使用不同的虛擬機器( virtual machine )時,此技術的實現方法也是不同的。在微軟的 JDK 1.1-compatible 虛擬機器 JView 中,微軟許可該密碼編譯演算法並提供了一個 HTTPS 流控制代碼作為它的 wininet 包的一部分。而SUN最近為它的 JDK 1.2-compatible 虛擬機器發布了 Java Secure Sockets Extension(JSSE),在 JSSE 裡許可並提供了 HTTPS 流控制代碼。本文將具體闡述如何使用 JSSE 和微軟的 wininet 包來實現 HTTPS 流控制代碼。

JDK 1.2-compatible 虛擬機器
在 JDK 1.2-compatible 虛擬機器中使用 HTTPS 的技術主要依賴於 Java Secure Sockets Extension(JSSE)1.0.1 版本。你必須先安裝 JSSE 並且將它添加到用戶端虛擬機器的類路徑中,才能夠使用這項技術。

當你安裝好 JSSE 之後,你必須設定一項系統屬性,將一個新的安全提供者添加到 Security 類對象。完成這項要求有若干種方法。鑒於這篇文章的目的,在這裡介紹一種實用方法:

System.setProperty("java.protocol.handler.pkgs",
"com.sun.net.ssl.internal.www.protocol");
Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());

完成以上兩個函數調用之後,運行如下所示代碼時將不再拋出 MalformedURLException 異常:

URL url = new URL("https://[your server]");

如果串連標準的SSL連接埠443,可以忽略在URL字串的後面添加連接埠號碼這一選項。但倘若你所串連的的Web伺服器採用非標準連接埠進行SSL通訊,就需要像下面這樣,在URL字串後面添加該連接埠號碼:

URL url = new URL("https://[your server]:7002");

有些伺服器擁有的可能是無簽名或非法的 SSL 證明書。倘若涉及這類伺服器的URL,使用此方法就需要注意。這種情況下,如果試圖從URL的連線物件中檢索輸入或輸出資料流時(例如運行以下代碼),就會拋出一個 SSLException 異常,並顯示 "untrusted server cer chain." 訊息。如果該伺服器擁有合法且有簽名的證明書,則不會拋出任何異常。

URL url = new URL("https://[your server]");
URLConnection con = URL.openConnection();
//SSLException thrown here if server certificate is invalid
con.getInputStream();

最顯而易見的解決上述問題的方法就是為你的伺服器取得一個簽名證明書。而 Java Developer Connectin forums 中為此問題成立了一個工作區,可以在這個URL地址中找到它們的相關資訊:http://forum.java.sun.com/forum?14@@.787ad8de.

Microsoft JView
由於微軟和Sun公司關於在 Windows 平台上使用 Java 的許可問題有爭論,微軟的 JView 虛擬機器現在僅僅是基於 JDK 1.1-compliant 的。而 JSSE 需要 1.2.2-compatible 或以上版本的虛擬機器,因此上述的方法並不適用於在 JView 上啟動並執行客戶機。但是微軟同樣也提供了足夠方便的 HTTPS 流控制代碼,將其作為 com.ms.net.wininet 包的一部分。

在 JView 環境中,只要為 URL 類調用一個簡單靜態函數就能夠設定 HTTPS 流控制代碼:

URL.setURLStreamHandlerFactory(new
com.ms.net.wininet.WininetStreamHandlerFactory());

執行以上的函數調用之後,再運行下面的代碼就不會拋出 MalformedURLException 異常:

URL url = new URL("https://[your server]");

使用這種方法需要注意兩點。首先,根據JDK的文檔,serURLStreamHandlerFactory 函數在一個虛擬機器上最多隻能被調用一次。之後的調用將會產生 Error。其次,正如在1.2虛擬機器解決方案中所說,使用那些指向無簽名或非法證明書的伺服器的 URL 時必須要謹慎。同前所述,這種情況下試圖向該 URL 地址的連線物件檢索輸入或輸出資料流時,就會出問題。不過微軟的流控制代碼拋出的是一個標準 IOExceptiony 異常,而不是 SSLException

URL url = new URL("https://[your server]");
URLConnection con = url.openConnection();
//IOException thrown here if server certificate is invalid
con.getInputStream();

同樣,解決此問題最顯而易見的方法就是僅和那些擁有簽名和合法證明書的伺服器進行通訊。不過JView還提供了另外一個選擇。將要向 URL 串連目標檢索輸入輸出資料流之前,你可以先為 connection 對象調用 setAllowUserInteraction(true) 函數。JView 在運行時就會顯示訊息,向使用者警告該伺服器的證明書是非法的,使用者可以選擇是否繼續。始終要記住的是,這樣的訊息在傳統型應用程式中是合乎情理的,但是除了調試的目的外,讓你的伺服器任何情況下都彈出訊息框可能是不可取的。

注意:你也可以在 JDK 1.2-compatible 版本的虛擬機器中調用 setAllowUserInteraction() 函數。不過,在Sun的1.2虛擬機器上(測試以下代碼),即使將該函數的參數設成true,也不會顯示訊息框。

URL url = new URL("https://[your server]");
URLConnection con = url.openConnection();
//causes the VM to display a dialog when connecting
//to untrusted servers
con.setAllowUserInteraction(true);
con.getInputStream();

在 Windows NT4.0 ,Windows2000 和 Windows9x 作業系統中,com.ms.net.wininet 包被預設安裝到系統的類路徑下。此外,根據微軟的JDK文檔,WinInetStreamHandlerFactory 是"… the same handler that is installed by default when running applets.",即運行applet時,同樣的流控制代碼也會被預設安裝。

平台獨立性
儘管上述的兩種方法覆蓋了大部分Java客戶程式可能啟動並執行平台,你的Java客戶程式也許需要在 JDK 1.1 和 JDK 1.2-compliant 虛擬機器上都可以正確運行。"寫一次,在任何地方運行,"還記得嗎?很自然會想到將這兩種方法結合起來,根據啟動並執行虛擬機器執行相應的處理控制代碼。下面的代碼展示了一種達到此目的的方法:

String strVendor = System.getProperty("java.vendor");
String strVersion = System.getProperty("java.version");
//Assumes a system version string of the form:
//[major].[minor].[release] (eg. 1.2.2)
Double dVersion = new Double(strVersion.substring(0, 3));

//If we are running in a MS environment, use the MS stream handler.
if( -1 < strVendor.indexOf("Microsoft") )
{
try
{
Class clsFactory =
Class.forName("com.ms.net.wininet.WininetStreamHandlerFactory" );
if ( null != clsFactory )
URL.setURLStreamHandlerFactory(
(URLStreamHandlerFactory)clsFactory.newInstance());
}
catch( ClassNotFoundException cfe )
{
throw new Exception("Unable to load the Microsoft SSL " +
"stream handler. Check classpath." + cfe.toString());
}
//If the stream handler factory has
//already been successfully set
//make sure our flag is set and eat the error
catch( Error err ){m_bStreamHandlerSet = true;}
}
//If we are in a normal Java environment,
//try to use the JSSE handler.
//NOTE: JSSE requires 1.2 or better
else if( 1.2 <= dVersion.doubleValue() )
{
System.setProperty("java.protocol.handler.pkgs",
"com.sun.net.ssl.internal.www.protocol");
try
{
//if we have the JSSE provider available,
//and it has not already been
//set, add it as a new provide to the Security class.
Class clsFactory = Class.forName("com.sun.net.ssl.internal.ssl.Provider");
if( (null != clsFactory) && (null == Security.getProvider("SunJSSE")) )
Security.addProvider((Provider)clsFactory.newInstance());
}
catch( ClassNotFoundException cfe )
{
throw new Exception("Unable to load the JSSE SSL stream handler." +
"Check classpath." + cfe.toString());
}
}

關於applets
在 applet 中進行基於 HTTPS 的通訊,看起來似乎是上述內容的自然擴充。事實上,在大多數情況下applet中的HTTPS通訊更易於實現。在 Netscape Navigator 和 Internet Explorer 的4.0或更高版本中,它們各自的虛擬機器都預設許可HTTPS協議。因此,倘若你要在applet代碼中建立一個HTTPS串連,只要在建立 URL執行個體時將協議名稱指定為"HTTPS"便可。

URL url = new URL("https://[your server]");

如果用戶端瀏覽器啟動並執行是Sun公司的Java 2外掛程式,那麼當你使用 HTTPS 時還會遇到一些其他限制。關於在Java 2外掛程式中使用 HTTPS 的詳細討論可以在Sun公司網站上找到(參看本文末的資料)。

結論
在應用程式中使用 HTTPS 協議,是一種快速而高效地在通訊中獲得足夠的安全性的方法。不幸的是,更多地出於法律而不是技術方面的原因,它沒有被標準 Java 規格說明書所支援。無論如何,隨著 JSSE 的產生以及微軟 com.ms.net.wininet 包的使用,在大多數的平台上只需要少許幾行代碼就能夠實現安全通訊。

關於作者
Matt Towers, 自稱為eBozo,最近離開了他在Visio的職位。此後加入華盛頓西雅圖的一個互連網公司PredictPoint.com ,在那裡從事全職的Java開發工作。

資料

  • 在本文中所描述的跨平台實現代碼,是在一個叫做HttpsMessage 類中實現的。HttpsMessageHttpMessage 類的子類。HttpMessage 類的作者是Jason Hunter,即Java Servlet Programming(O'Reilly & Associates) 一書的作者. 在他即將出版的該書第二版中,你可以找到HttpsMessage 類。如果想要繼承此類,必須下載並安裝com.oreily.servlets 包。這個包以及相關子原始碼可以在Hunter的網站上找到:
    http://www.servlets.com
  • 你也可以下載HttpsMessage 類源碼的壓縮檔:
    HttpsMessage.zip
  • 以下是若干用於測試HTTPS通訊的網頁地址:
    • https://www.verisign.com/
    • https://happiness.dhs.org/
    • https://www.microsoft.com
    • https://www.sun.com
    • https://www.ftc.gov
  • 更多關於JSSE、可下載位和安裝指令的資訊可以在Sun公司的網站上找到:
    http://java.sun.com/products/jsse/.
  • 關於如何使用一些JSSE服務的描述,包括上文所提到的方法,都可以在O'Reilly網站上Jonathan Knudsen 所編寫的"Secure Networking in Java"中找到:
    http://java.oreilly.com/bite-size/java_1099.html
  • 更多關於WininetStreamHandlerFactory 類的資訊可以在微軟的JSDK文檔中找到:http://www.microsoft.com/java/sdk/。此外,Microsoft knowledge base還出版了"PRB: Allowing the URL class to access HTTPS in Applications":
    http://support.microsoft.com/support/kb/articles/Q191/1/20.ASP
  • 關於在Java 2外掛程式中使用HTTPS的更多資訊可以在Sun網站的"How HTTPS Works in Java Plug-In "中找到:
    http://java.sun.com/products/plugin/1.2/docs/https.html

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.