1. 概述
本教程演示瞭如何使用 Spring 的 Channel Security 功能,通過 HTTPS 來保護應用程序的登錄頁。
使用 HTTPS 進行身份驗證對於在傳輸過程中保護敏感數據完整性至關重要。
本文檔基於 Spring Security 登錄教程,增加了額外的安全層。我們重點介紹了通過編碼的 HTTPS 渠道提供登錄頁面的步驟。
2. 不啓用通道安全時的初始設置
讓我們從之前文章中解釋的安全配置開始。
該Web應用程序允許用户訪問:
- /anonymous.html,無需身份驗證;
- /login.html,以及
- 登錄成功後,其他頁面(/homepage.html)。
訪問權限由以下配置控制:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/anonymous*")
.anonymous();
http.authorizeRequests()
.antMatchers("/login*")
.permitAll();
http.authorizeRequests()
.anyRequest()
.authenticated();
或者通過XML:
<http use-expressions="true">
<intercept-url pattern="/anonymous*" access="isAnonymous()"/>
<intercept-url pattern="/login*" access="permitAll"/>
<intercept-url pattern="/**" access="isAuthenticated()"/>
</http>此時,登錄頁面可用地址如下:
http://localhost:8080/spring-security-login/login.html用户可以通過HTTP進行身份驗證,但這種方式不安全,因為密碼會以明文形式發送。
3. HTTPS 服務器配置
為了僅通過 HTTPS 提供登錄頁面,您的 Web 服務器必須能夠提供 HTTPS 頁面。 這需要啓用 SSL/TLS 支持。
請注意,您可以使用有效的證書,或者,僅用於測試目的,您可以生成自己的證書。
假設我們使用 Tomcat 並自行生成證書。 我們首先需要創建一個 keystore,其中包含自簽名證書。
在終端中發出以下命令可以生成 keystore:
keytool -genkey -alias tomcat -keyalg RSA -storepass changeit -keypass changeit -dname 'CN=tomcat'這將創建一個私鑰和一個自簽名證書,保存在您的用户配置文件中,位於您的家目錄。
下一步是編輯 conf/server.xml,使其內容如下所示:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="${user.home}/.keystore" keystorePass="changeit" />第二個 SSL/TLS <Connector> 標籤通常在配置文件中被註釋掉,只需取消註釋並添加密鑰庫信息即可。更多信息請參考 Apache Tomcat 的相關文檔。
HTTPS 配置完成後,登錄頁面也可以通過以下 URL 提供:
https://localhost:8443/spring-security-login/login.html其他非Tomcat的Web服務器需要不同的配置,但配置方式可能相似。
4. 配置通道安全
在此階段,我們已經能夠同時在HTTP和HTTPS下提供登錄頁面。本節將解釋如何強制使用HTTPS。
為了強制登錄頁面使用HTTPS,請修改您的安全配置,添加以下內容:
http.requiresChannel()
.antMatchers("/login*").requiresSecure();或者,將 requires-channel=”https” 屬性添加到您的 XML 配置中:
<intercept-url pattern="/login*" access="permitAll" requires-channel="https"/>在此之後,用户只能通過 HTTPS 登錄。所有相對鏈接,例如指向 /homepage.html 的鏈接,都將繼承原始請求的協議並以 HTTPS 方式提供。
當單個 Web 應用程序中混合使用 HTTP 和 HTTPS 請求時,需要注意並進行進一步配置的額外方面。
5. 混合使用 HTTP 和 HTTPS
從安全角度來看,一切都使用 HTTPS 是一個好習慣,也是一個值得追求的目標。
但是,如果僅使用 HTTPS 並非選項,我們可以配置 Spring 使用 HTTP,通過在配置中添加以下內容:
http.requiresChannel()
.anyRequest().requiresInsecure();或者將 屬性添加到 XML 中:
<intercept‐url pattern="/**" access="isAuthenticated()" requires‐channel="http"/>這指示 Spring 使用 HTTP 處理所有未明確配置為使用 HTTPS 的請求,但同時破壞了原始的登錄機制。以下部分解釋了其根本原因。
5.1. 自定義登錄處理 URL 使用 HTTPS
原始安全教程中的安全配置包含以下內容:
<form-login login-processing-url="/perform_login"/>避免強制/perform_login使用HTTPS,否則將會重定向到其HTTP變體,從而丟失通過原始請求發送的登錄信息。
為了解決這個問題,我們需要配置Spring使用HTTPS處理URL:
http.requiresChannel()
.antMatchers("/login*", "/perform_login");請注意,/perform_login 額外參數已傳遞到 antMatchers 方法。
在 XML 配置中,需要添加新的 <intercept-url> 元素到配置中:
<intercept-url pattern="/perform_login" requires-channel="https"/>如果您的應用程序使用默認的 login-processing-url(默認為 /login),則無需顯式配置此項,因為 /login* 模式已經涵蓋了這種情況。
配置完成後,用户可以登錄,但無法通過 HTTP 協議訪問受認證的頁面,例如 /homepage.html,這是由於 Spring 的會話固定保護功能造成的 Spring 的會話固定保護功能。
5.2. 禁用 session-fixation-protection
會話固定攻擊 是一種在 HTTP 和 HTTPS 之間切換時無法避免的問題。
Spring 默認會在成功登錄後創建一個新的 session-id。當用户加載 HTTPS 登錄頁面時,用户的 session-id cookie 會被標記為 secure。登錄後,上下文會切換到 HTTP,並且 cookie 會在 HTTP 中丟失,因為 HTTP 不安全。
為了避免這種情況,需要將 session-fixation-protection 設置為 none。
http.sessionManagement()
.sessionFixation()
.none();或者通過XML:
<session-management session-fixation-protection="none"/>
禁用會話固定保護可能會產生安全影響,因此如果您擔心會話固定攻擊,則需要權衡利弊。
6. 測試
在應用所有這些配置更改後,通過訪問 /anonymous.html 而無需登錄(使用 http:// 或 https://)將通過 HTTP 轉發您到該頁面。
直接打開其他頁面,如 /homepage.html,應該會通過 HTTPS 轉發您到登錄頁面,登錄後您將使用 HTTP 轉發回 /homepage.html。
7. 結論
在本教程中,我們學習瞭如何配置通過 HTTP 進行通信的 Spring Web 應用程序,但對於登錄機制除外。然而,現代 Web 應用程序幾乎總是應使用 HTTPS 作為其通信協議。降低安全級別或禁用安全功能(如 會話固定保護)都是不可取的。