天天看點

Spring Security(13)——session管理

目錄

<a href="#_Toc418542267">1.1     檢測session逾時</a>

<a href="#_Toc418542268">1.2     concurrency-control</a>

<a href="#_Toc418542269">1.3     session 固定攻擊保護</a>

       Spring Security通過http元素下的子元素session-management提供了對Http Session管理的支援。

       Spring Security可以在使用者使用已經逾時的sessionId進行請求時将使用者引導到指定的頁面。這個可以通過如下配置來實作。

   &lt;security:http&gt;

      ...

      &lt;!-- session管理,invalid-session-url指定使用已經逾時的sessionId進行請求需要重定向的頁面 --&gt;

      &lt;security:session-management invalid-session-url="/session_timeout.jsp"/&gt;

   &lt;/security:http&gt;

       需要注意的是session逾時的重定向頁面應當是不需要認證的,否則再重定向到session逾時頁面時會直接轉到使用者登入頁面。此外如果你使用這種方式來檢測session逾時,當你退出了登入,然後在沒有關閉浏覽器的情況下又重新進行了登入,Spring Security可能會錯誤的報告session已經逾時。這是因為即使你已經登出了,但當你設定session無效時,對應儲存session資訊的cookie并沒有被清除,等下次請求時還是會使用之前的sessionId進行請求。解決辦法是顯示的定義使用者在登出時删除對應的儲存session資訊的cookie。

      &lt;!-- 登出時删除session對應的cookie --&gt;

      &lt;security:logout delete-cookies="JSESSIONID"/&gt;

       此外,Spring Security并不保證這對所有的Servlet容器都有效,到底在你的容器上有沒有效,需要你自己進行實驗。

       通常情況下,在你的應用中你可能隻希望同一使用者在同時登入多次時隻能有一個是成功登入你的系統的,通常對應的行為是後一次登入将使前一次登入失效,或者直接限制後一次登入。Spring Security的session-management為我們提供了這種限制。

       首先需要我們在web.xml中定義如下監聽器。

   &lt;listener&gt;

   &lt;listener-class&gt;org.springframework.security.web.session.HttpSessionEventPublisher&lt;/listener-class&gt;

   &lt;/listener&gt;

       在session-management元素下有一個concurrency-control元素是用來限制同一使用者在應用中同時允許存在的已經通過認證的session數量。這個值預設是1,可以通過concurrency-control元素的max-sessions屬性來指定。

   &lt;security:http auto-config="true"&gt;

      &lt;security:session-management&gt;

         &lt;security:concurrency-control max-sessions="1"/&gt;

      &lt;/security:session-management&gt;

       當同一使用者同時存在的已經通過認證的session數量超過了max-sessions所指定的值時,Spring Security的預設政策是将先前的設為無效。如果要限制使用者再次登入可以設定concurrency-control的error-if-maximum-exceeded的值為true。

         &lt;security:concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/&gt;

       設定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”。

   &lt;security:http security="none" pattern="/none/**" /&gt;

      &lt;security:form-login/&gt;

      &lt;security:logout/&gt;

      &lt;security:intercept-url pattern="/**" access="ROLE_USER"/&gt;

      &lt;!-- session-authentication-error-url必須是不受Spring Security管理的 --&gt;

      &lt;security:session-management session-authentication-error-url="/none/session_authentication_error.jsp"&gt;

      &lt;security:remember-me data-source-ref="dataSource"/&gt;

       在上述配置中我們配置了session-authentication-error-url為“/none/session_authentication_error.jsp”,同時我們通過&lt;security:http security="none" pattern="/none/**" /&gt;指定了以“/none”開始的所有URL都不受Spring Security控制,這樣當使用者進行登入以後,再次通過Remember-Me進行自動登入時就會重定向到“/none/session_authentication_error.jsp”了。

       在上述配置中為什麼我們需要通過&lt;security:http security="none" pattern="/none/**" /&gt;指定我們的session-authentication-error-url不受Spring Security控制呢?把它換成&lt;security:intercept-url pattern="/none/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/&gt;不行嗎?這就涉及到之前所介紹的它們兩者之間的差別了。前者表示不使用任何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應當使用&lt;security:http security="none" pattern="/none/**" /&gt;設定為不受Spring Security控制,而不是使用&lt;security:intercept-url pattern="/none/**" access="IS_AUTHENTICATED_ANONYMOUSLY"/&gt;。

       此外,可以通過expired-url屬性指定當使用者嘗試使用一個由于其再次登入導緻session逾時的session時所要跳轉的頁面。同時需要注意設定該URL為不需要進行認證。

      &lt;security:intercept-url pattern="/expired.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/&gt;

         &lt;security:concurrency-control max-sessions="1" expired-url="/expired.jsp" /&gt;

       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所寫)