1.1 檢測session超時
1.2 concurrency-control
1.3 session 固定攻擊保護
Spring Security通過http元素下的子元素session-management提供了對Http Session管理的支持。
1.1 檢測session超時
Spring Security可以在用戶使用已經超時的sessionId進行請求時將用戶引導到指定的頁面。這個可以通過如下配置來實現。
<security:http>
...
<!-- session管理,invalid-session-url指定使用已經超時的sessionId進行請求需要重定向的頁面 -->
<security:session-management invalid-session-url="/session_timeout.jsp"/>
...
</security:http>
需要注意的是session超時的重定向頁面應當是不需要認證的,否則再重定向到session超時頁面時會直接轉到用戶登錄頁面。此外如果你使用這種方式來檢測session超時,當你退出了登錄,然后在沒有關閉瀏覽器的情況下又重新進行了登錄,Spring Security可能會錯誤的報告session已經超時。這是因為即使你已經退出登錄了,但當你設置session無效時,對應保存session信息的cookie並沒有被清除,等下次請求時還是會使用之前的sessionId進行請求。解決辦法是顯示的定義用戶在退出登錄時刪除對應的保存session信息的cookie。
<security:http>
...
<!-- 退出登錄時刪除session對應的cookie -->
<security:logout delete-cookies="JSESSIONID"/>
...
</security:http>
此外,Spring Security並不保證這對所有的Servlet容器都有效,到底在你的容器上有沒有效,需要你自己進行實驗。
1.2 concurrency-control
通常情況下,在你的應用中你可能只希望同一用戶在同時登錄多次時只能有一個是成功登入你的系統的,通常對應的行為是后一次登錄將使前一次登錄失效,或者直接限制后一次登錄。Spring Security的session-management為我們提供了這種限制。
首先需要我們在web.xml中定義如下監聽器。
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
在session-management元素下有一個concurrency-control元素是用來限制同一用戶在應用中同時允許存在的已經通過認證的session數量。這個值默認是1,可以通過concurrency-control元素的max-sessions屬性來指定。
<security:http auto-config="true">
...
<security:session-management>
<security:concurrency-control max-sessions="1"/>
</security:session-management>
...
</security:http>
當同一用戶同時存在的已經通過認證的session數量超過了max-sessions所指定的值時,Spring Security的默認策略是將先前的設為無效。如果要限制用戶再次登錄可以設置concurrency-control的error-if-maximum-exceeded的值為true。
<security:http auto-config="true">
...
<security:session-management>
<security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/>
</security:session-management>
...
</security:http>
設置error-if-maximum-exceeded為true后如果你之前已經登錄了,然后想再次登錄,那么系統將會拒絕你的登錄,同時將重定向到由form-login指定的authentication-failure-url。如果你的再次登錄是通過Remember-Me來完成的,那么將不會轉到authentication-failure-url,而是返回未授權的錯誤碼401給客戶端,如果你還是想重定向一個指定的頁面,那么你可以通過session-management的session-authentication-error-url屬性來指定,同時需要指定該url為不受Spring Security管理,即通過http元素設置其secure=”none”。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
<
security:http
security="none" pattern="/none/**" />
<
security:http
>
<
security:form-login
/>
<
security:logout
/>
<
security:intercept-url
pattern="/**" access="ROLE_USER"/>
<!-- session-authentication-error-url必須是不受Spring Security管理的 -->
<
security:session-management
session-authentication-error-url="/none/session_authentication_error.jsp">
<
security:concurrency-control
max-sessions="1" error-if-maximum-exceeded="true"/>
</
security:session-management
>
<
security:remember-me
data-source-ref="dataSource"/>
</
security:http
>
|
在上述配置中我們配置了session-authentication-error-url為“/none/session_authentication_error.jsp”,同時我們通過<security:http security="none" pattern="/none/**" />指定了以“/none”開始的所有URL都不受Spring Security控制,這樣當用戶進行登錄以后,再次通過Remember-Me進行自動登錄時就會重定向到“/none/session_authentication_error.jsp”了。
在上述配置中為什么我們需要通過<security:http security="none" pattern="/none/**" />指定我們的session-authentication-error-url不受Spring Security控制呢?把它換成<security:intercept-url pattern="/none/**"access="IS_AUTHENTICATED_ANONYMOUSLY"/>不行嗎?這就涉及到之前所介紹的它們兩者之間的區別了。前者表示不使用任何Spring Security過濾器,自然也就不需要通過Spring Security的認證了,而后者是會被Spring Security的FilterChain進行過濾的,只是其對應的URL可以匿名訪問,即不需要登錄就可訪問。使用后者時,REMEMBER_ME_FILTER檢測到用戶沒有登錄,同時其又提供了Remember-Me的相關信息,這將使得REMEMBER_ME_FILTER進行自動登錄,那么在自動登錄時由於我們限制了同一用戶同一時間只能登錄一次,后來者將被拒絕登錄,這個時候將重定向到session-authentication-error-url,重定向訪問session-authentication-error-url時,經過REMEMBER_ME_FILTER時又會自動登錄,這樣就形成了一個死循環。所以session-authentication-error-url應當使用<security:http security="none" pattern="/none/**" />設置為不受Spring Security控制,而不是使用<security:intercept-url pattern="/none/**"access="IS_AUTHENTICATED_ANONYMOUSLY"/>。
此外,可以通過expired-url屬性指定當用戶嘗試使用一個由於其再次登錄導致session超時的session時所要跳轉的頁面。同時需要注意設置該URL為不需要進行認證。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
<
security:http
auto-config="true">
<
security:form-login
/>
<
security:logout
/>
<
security:intercept-url
pattern="/expired.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<
security:intercept-url
pattern="/**" access="ROLE_USER"/>
<
security:session-management
>
<
security:concurrency-control
max-sessions="1" expired-url="/expired.jsp" />
</
security:session-management
>
</
security:http
>
|
1.3 session 固定攻擊保護
session固定是指服務器在給客戶端創建session后,在該session過期之前,它們都將通過該session進行通信。session 固定攻擊是指惡意攻擊者先通過訪問應用來創建一個session,然后再讓其他用戶使用相同的session進行登錄(比如通過發送一個包含該sessionId參數的鏈接),待其他用戶成功登錄后,攻擊者利用原來的sessionId訪問系統將和原用戶獲得同樣的權限。Spring Security默認是對session固定攻擊采取了保護措施的,它會在用戶登錄的時候重新為其生成一個新的session。如果你的應用不需要這種保護或者該保護措施與你的某些需求相沖突,你可以通過session-management的session-fixation-protection屬性來改變其保護策略。該屬性的可選值有如下三個。
l migrateSession:這是默認值。其表示在用戶登錄后將新建一個session,同時將原session中的attribute都copy到新的session中。
l none:表示繼續使用原來的session。
l newSession:表示重新創建一個新的session,但是不copy原session擁有的attribute。
(注:本文是基於Spring Security3.1.6所寫)
Java設置session超時(失效)的時間
在一般系統登錄后,都會設置一個當前session失效的時間,以確保在用戶長時間不與服務器交互,自動退出登錄,銷毀session
具體設置的方法有三種:
1.在web容器中設置(以tomcat為例)
在tomcat-7.0\conf\web.xml中設置,以下是tomcat7.0中默認配置:
1
2
3
|
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
|
tomcat默認session超時時間為30分鍾,可以根據需要修改,負數或0為不限制session失效時間
這里要注意這個session設置的時間是根據服務器來計算的,而不是客戶端。所以如果在調試程序,應該是修改服務器端時間來測試,而不是客戶端
2.在工程的web.xml中設置
<!--時間單位為分鍾-->
1
2
3
|
<session-config>
<session-timeout>
15
</session-timeout>
</session-config>
|
這里的15是指15分鍾失效
3.通過java代碼設置
session.setMaxInactiveInterval(30*60);//以秒為單位,即在沒有活動30分鍾后,session將失效
三種方式優先等級:1 < 2 < 3