切換到SSL再切換回來
Switch to SSL and back again
◆ 問題
怎樣在應用程序中使用SSL。
◆ 背景
大多數組織把信息資料當作他們的最寶貴的資產。保護信息的工作不僅僅是象開發者和管理員似的一個專職的工作而已。信息的保護必須從許多不同的角度實施。數據庫,用戶界面和商業層只是這些需要你注意的關鍵領域的某些方面。甚至通往服務器機房的門都必須被鎖住。更重要的是,一旦這些數據經由因特網離開了這些建築物,它的安全就會被一些很有才能的在網絡上用電子手段刺探的人危及。
在本方法中,我們示範怎樣在容器中啓動Secure Socket Layer (SSL)。另外,我們爲你介紹Struts SSL 的擴展,HTTP/HTTPS切換庫——一個允許你聲明哪些Action啓用了SSL 的程序包。這個很好用的程序包允許你在SSL-激活的Action和禁止的Action之間很容易地轉換。
進入本方法之前,讓我們涉及一些SSL 基礎。SSL原來是一個由Netscape 開發的網絡協議,來提供認證和傳輸保密性。SSL 協議屬於TCP/IP之上的網絡層,但是低於應用協議,比如HTTP ,LDAP和IMAP。在傳送前客戶端檢驗服務器的身份。 類似的,服務器端也可能可選地檢驗客戶端的身份。爲了阻斷數字偷聽者的努力,這兩個主機就一個密碼算法達成一致協議,通常叫做一個密碼,來加密和解密傳送的數據。除提供機密性之外,SSL 對傳送過程進行審計,來保證傳輸的數據在途中未被篡改。整個SSL 的工作方式超出了這個方法的範圍,但是我們鼓勵你利用一些在資源部分提到的資源探索SSL。
大多數容器,包括Tomcat ,提供SSL 服務。在你容器上啓動SSL 確保你的通訊是安全的和不被篡改的。容器能通過檢查URL 方案識別出SSL 通訊。URL 方案是URL 中冒號前面的那部分。HTTP 非保密協議是用冒號之前的“HTTP”識別的。例如,http://127.0.0.1指出一個非保密http 協議。一個“s”放置在http 後,來表明該請求希望使用SSL 傳送。例如,https://127.0.0.1是用於一個SSL http 請求的適當的URL。
許多應用程序兼具SSL 和非SSL連接。這裏面的挑戰是當你要一個安全通信的時候,怎樣格式化你的連接成爲SSL 。作爲默認,Struts 鏈接標籤使用與你正在瀏覽的當前頁面相同的URI 方案。所以,如何從一個安全的頁面到一個不安全的頁面建立一個鏈接,或者反過來怎麼做呢?一個選擇是建立你自己的鏈接標籤來寫SSL 鏈接,但是這會迅速地導致維護的負擔,只要你需要把鏈接從一個轉變到另一個的任何時候。現在如果你能通過在struts-config.xml 文件中聲明來做這個,你會成爲一個幸福的露營者了。你可以使用標籤來寫你的鏈接,但是一旦情況發生變化,你可以在struts-config.xml 文件中聲明性地改變它們。很幸運,那剛好是Struts SSL HTTP/HTTPS 切換擴展庫爲你做的。在這個方法中,我們展示怎樣用Tomcat 設立SSL。然後我們展示怎樣在你的應用程序中設立和使用ssl-ext 來加密網上傳輸的數據。完整的SSL 認證的說明超出了本書的範圍;實際上,我們集中在Struts 開發的SSL方面。
◆ 方法
本方法的實現被分成三個部分。在前邊部分我們展示怎樣在Tomcat 上啓動SSL 。接下來,我們描述究竟需要做什麼來完成在你的應用程序中安裝SSL-ext。最後,我們在代碼中應用SSL-ext。現在開始!
步驟1:在Tomcat 上啓動SSL
1 從http://java.sun.com/products/jsse/下載並安裝JSSE 1.0.2(或者更新的版本)。此網址告訴你安裝JSSE必須知道的所有動作。注意,Java 2 SDK Standard Edition v1.4已經預先捆綁了JSSE。如果你正在使用JDK v1.4,你可以跳個過這個步驟。
2 創建一個證書keystore(密鑰倉庫)。鍵入以下命令之一:
對Windows:
%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keyalg RSA -keystore D:\server.keystore -validity 365
對UNIX: $JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA
你會被問到許多問題。作爲練習目的,僅僅鍵入對你來說有意義的無論什麼都可以。當要實現到一個受控環境中時,找你的系統管理員。
3 從conf/server.xml 中取消SSL HTTP/1.1 Connector 的註釋。該被取消註釋的連接器應該看起來像這樣(特別地,記下端口號,隨後必須知道):
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="D:/server.keystore"
keystorePass="changeit" />
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
4 重新啓動Tomcat。用瀏覽器訪問https://127.0.0.1:8443來確定所有動作如設計運行。如果Tomcat 顯示該頁面,那麼就奏效了。
祝賀,你已經在Tomcat 上激活了SSL。
步驟2:爲應用程序設置Struts SSL HTTP/HTTPS 切換擴展(SSL-ext)
因爲ssl-ext 是一個Struts 擴展庫,它的安裝與Struts類似就不奇怪了。如果你已經安裝了Struts,以下用法說明會似曾相識。
1 從http://sslext.sourceforge.net 下載ssl-ext 包。該包包含一個可工作的樣例應用程序。把下載包Unzip 到Tomcat webapps 目錄。在以下步驟中,你要從樣例應用程序複製許多文件來創建你自己的ssl-ext 應用程序。
2 把sslext.jar 文件從樣例應用程序複製到WEB-INF/lib 目錄中。
3 把sslext.tld 文件從樣例應用程序複製到你的WEB-INF/lib 目錄中。
4 把以下片斷和其他taglib一起放在web.xml 文件中:
<taglib>
<taglib-uri>/WEB-INF/sslext.tld</taglib-uri>
<taglib-location>/WEB-INF/sslext.tld</taglib-location>
</taglib>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!-- 配置ssl的tld --> <jsp-config>
<taglib>
<taglib-uri>/WEB-INF/sslext.tld</taglib-uri>
<taglib-location>/WEB-INF/sslext.tld</taglib-location>
</taglib>
</jsp-config>
5 把插件標籤添加到struts-config.xml 文件中。特別記下httpsPort 屬性。它必須與用來配置Tomcat 的相同(步驟1,說明3)。如你可能預期的,該httpPort 屬性應該和在conf/server.xml 中找到的Tomcat 配置相配。下列兩個定義的值是Tomcat 的值。
<plug-in className="org.apache.struts.action.SecurePlugIn">
<set-property property="httpPort" value="8080"/>
<set-property property="httpsPort" value="8443"/>
<set-property property="enable" value="true"/>
</plug-in>
做完這些,你隨時可以開始使用ssl-ext了。
步驟3:使用ssl-ext 建立一個應用程序
我們通過建立一個應用程序來示範ssl-ext 運轉。在這個步驟中,我們展示ssl-ext 是如何被用來爲指向ssl 安全頁面的鏈接格式化URL 的。相反的,我們示範爲指向普通的非SSL頁面的鏈接格式化URL。我們將知道給頁面提供安全保障是通過對struts-config.xml 做一個小的改變完成的。清單7.6 展示struts-config.xml 對應一個示例應用程序的動作映射。
清單7.6 Struts-config.xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<global-forwards type="org.apache.struts.action.ActionForward">
<forward name="unsecured" path="/unsecured.do"/>
<forward name="secured" path="/secured.do"/>
<forward name="menu" path="/menu.do"/>
</global-forwards>
<form-beans>
<form-bean name="dummyForm" type="com.strutsrecipes.ssl.forms.Dummy" />
</form-beans>
<action-mappings type="org.apache.struts.config.SecureActionConfig">
<action path="/menu"
type="org.apache.struts.actions.ForwardAction"
parameter="/WEB-INF/pages/menu.jsp">
<set-property property="secure" value="false"/>
</action>
<action path="/unsecured"
type="org.apache.struts.actions.ForwardAction"
parameter="/WEB-INF/pages/unsecured.jsp">
<set-property property="secure" value="false"/>
</action>
<action path="/secured"
type="org.apache.struts.actions.ForwardAction"
parameter="/WEB-INF/pages/secured.jsp">
<set-property property="secure" value="true"/>
</action>
<action path="/securesubmit"
type="org.apache.struts.actions.ForwardAction"
name="dummyForm"
parameter="/WEB-INF/pages/securesubmit.jsp">
<set-property property="secure" value="true"/>
</action>
<action path="/unsecuresubmit"
type="org.apache.struts.actions.ForwardAction"
name="dummyForm"
parameter="/WEB-INF/pages/unsecuresubmit.jsp">
<set-property property="secure" value="false"/>
</action>
</action-mappings>
<plug-in className="org.apache.struts.action.SecurePlugIn">
<set-property property="httpPort" value="8080"/>
<set-property property="httpsPort" value="8443"/>
<set-property property="enable" value="true"/>
</plug-in>
</struts-config>
要用SSL 使一個Action 安全,把一個<set-property>標籤嵌套在Action 標籤內。 該property 屬性的值永遠是secure。該值屬性的true 值表明我們需要URL通過設置URI 方案“https”來發出一個SSL 請求。類似的,false 值表明該頁面是普通的不安全的頁面;該URI 方案應該是“http”。一個any 值默認表示採用當前頁的方案。雖然你可以使
用一個普通的Struts 鏈接標籤達到相同效果,但是該any 值讓你可以通過修改Struts-config 文件把它改成true 或者false 。
因爲該安全屬性不被默認動作映射支持,我們需要在(處)重載它。清單7.7示範ssl-ext 鏈接標籤如何被用來產生一個協議格式的URL 。
清單7.7 menu.jsp: JSP 使用 ssl-ext 鏈接標籤
<%@ page language="java" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%>
<%@ taglib uri="/WEB-INF/sslext.tld" prefix="sslext"%>
<html:html>
<h1>SSL: Menu</h1>
<h2>Links</h2>
<br><sslext:link forward="unsecured">unsecured</sslext:link>
<br><sslext:link forward="secured">secured</sslext:link>
<h2>submit to secured</h2>
<sslext:form action="/securesubmit" >
<br><html:text property="name" value=""/>
<html:submit/>
</sslext:form>
<h2>submit to unsecured</h2>
<sslext:form action="/unsecuresubmit" >
<br><html:text property="name" value=""/>
<html:submit/>
</sslext:form>
</html:html>
指向安全頁面的鏈接前綴https ,指向不安全的的頁面的鏈接被格式化成通常的http 。例如,在處的鏈接顯示爲“不安全的”http://127.0.0.1:8080/ssl/unsecured.do,而在處的鏈接顯示爲“安全的”https://127.0.0.1:8443/ssl/secured.do。
在清單7.7中最顯著的結果是我們從未指定頁面使用SSL,是否是安全的。該信息是定義在struts-configxml 文件中的。在清單7.7中處的鏈接標籤映射到清單7.6的處。相似的,處映射到處,處映射到處,處映射到處。當寫URL 的協議段的時候,該ssl:ext 鏈接標籤查閱struts-config.xml 文件。要使用該ssl-ext taglib,你需要像我們在處已經做的那樣聲明它。
提交工作以大體上相同的方式進行,只是你必須從ssl-ext 名字空間(處)(處)使用表單標籤。
到這裏,應用ssl-ext 的過程在上述步驟中得到完全解決。
◆ 討論
因爲步驟1和步驟2是顯而易見的,我們無需回顧那些部分。步驟3更有意思得多,並且值得仔細考察。JSP 的工作很簡單,不考慮sslext 名字空間的話,它看起來幾乎無異於任何Struts JSP 。代替用Struts 鏈接標籤寫鏈接的是我們使用sslext 名字空間當中相同的標籤。在這些場景後面,這些標籤是使用動作映射來把URI 方案設置爲http 或者https 的。要用https 寫URL,把動作映射上的secure 屬性設置爲true。要把URL 寫成“http”,把它設置爲false。提交的過程也是一樣,只是你使用sslext 名字空間的表單標籤而不是Struts 的html 名字空間。
還有一個標籤我們尚未討論過。pageScheme標籤使用secure屬性 來強制一個到http 或者https 的重定向。例如,一個到<sslext:pageScheme secure="false">的頁面的https 請求重定向該請求到http,而不管實際上該請求是用https發起的。
如果沒有ssl-ext,用以保證URL 使用正確前綴方案的工作將會更加困難。代替通過在JSP 中修整每個ssl 鏈接來處理這個問題的是,我們可以從struts-conf. xml 文件中來管理它。如此,維護性方面的報償是很客觀的。例如,如果我們有到相同Struts Action 的20個鏈接,那麼爲了改變鏈接以使用SSL,必須對20個JSP 做改變。同等的改變在ssl-ext 下只需要對struts-config.xml的僅僅一個改動!犯太多罪過的是人,避免錯誤的是神。
最優方法
審慎地使用SSL——SSL 是一個認證和使應用程序安全的已被證實的、可靠的、靈活的,並且流行的辦法,但是你應該僅當需要時才使用它。所有SSL 的傳送都加密並解密數據。取決於選擇的密碼,這些運算會影響應用程序的性能。