05 July 2006

呃... 趁還沒忘記前先記下來。

第一步:欲限定特定的網頁資源走 https,可以在 web.xml 裡設定:

<security-constraint>
   <web-resource-collection>
        <url-pattern>/manage/changePassword.jsp</url-pattern>
   </web-resource-collection>
   <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
   </user-data-constraint>
</security-constraint>

上面設定當網址出現 /manage/changePassword.jsp 時,會強制 redirect 成 https (因為設 CONFIDENTIAL)。當然,url-pattern 處可以用 wild card 代表更多資源。security-constraint 也可以重覆設多個,我測試的結果是先 match 的 pattern 先贏。

第二步:設定 tomcat/conf/server.xml,先將 SSL connector uncomment,並且保留 port="8443" :

    <!-- Define a SSL HTTP/1.1 Connector on port 8443 -->
    <!-- uncomment 掉
    <Connector port="8443" maxHttpHeaderSize="8192" .... />
    --> uncomment 掉 

現在我們有兩個 connector 了,一個是 8080 port,另一個是 8443 port。再來,將 non-SSL connector 的 redirect port 改成 443 (注意,不是8443):

    <!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
    <Connector port="8080" maxHttpHeaderSize="8192"
               ..... 
               redirectPort="443" /> (改成 443)

按這樣的設定,當遇到 /manage/changePassword.jsp 時,如果 server 發現是走 http,就會轉到 https,並且使用 443 port。

第三步,如果公司沒有 certificate keystore 檔的話,要自己做一個供 SSL 使用 :

  keytool -genkey -alias tomcat -keyalg RSA -validity 365 

keytool 這個工具新的 jdk 裡都有。問到 Common Name 時 (就是名字),請填 server 的網址。而問到密碼時,則都用 'changeit' ,這是 tomcat 預設的密碼。上面的 -validity 365 則表示憑證有效期限 365 天。完成後會在家目錄裡建立一個 .keystore 檔。tomcat 啟動時,預設會去找啟動者的家目錄底下的 .keystore 來用。

第四步,設定 iptables 將 80 port 導至 8080 port;將 443 port 導至 8443 port。linux 的環境裡 1024 號以下的 port 只有 root 可以用,因此只能靠間接的方式:

iptables -t nat -A PREROUTING -p tcp --dport 80 -i eth0 -j REDIRECT --to-port 8080
iptables -t nat -A PREROUTING -p tcp --dport 443 -i eth0 -j REDIRECT --to-port 8443

這兩行可以加在 firewall 的相關設定檔裡,這樣一開機就自動生效。注意 PREROUTING 在本機端無效,因此測試時要找別台機器來試。

這樣就完成了,可以開啟 tomcat 來測試。

  • Case1: 當我們用 http://foo.com/myapp/pageA.jsp 連時,linux 會將 80 port 接到的資料導到 tomcat 8080 connector,完成 request。
  • Case2: 當我們用 https://foo.com/myapp/manage/changePassword.jsp 連時,linux 會將 443 port 接到的資料導到 tomcat 8443 connector,完成 request。
  • Case3: 當我們用 http://foo.com/myapp/manage/changePassword.jsp 連時,linux 會將 80 port 導到 tomcat 8080 port,而依 web.xml 設定,這個網址要走 https,這時會再被 tomcat 8080 connector 導至 443 port。linux 在接到 443 port 後,再導到 8443 port,最後 tomcat 8443 connector 才接到資料,完成 request。整個 request 經過: 80 --iptables--> 8080 --tomcat connetor --> 443 --iptables--> 8443 的轉換。

注意:

  • 此法僅適用於單機 tomcat,如果有 apache,那就可以將轉 port 的設定都交給 apache 來做。
  • 利用 security-constraint 來轉址的網頁,在轉完網址後並不會離開 https,這部份目前還找不到該怎麼設定。有需要的話,現階段可以用 Acegi 的 ChannelProcessingFilter 來達成。

回響

可以用 Tag <I>、<B>,程式碼請用 <PRE>