單點登錄

在講單點登錄之前,我們先來看看cookie與session :

cookie是通過瀏覽器保存在客戶端的臨時數據,一般這些數據對安全的要求不高,雖然可以通過加密存放和SSL方式提交的方式加強cookie的安全,但不代表cookie就是百分之百安全的。再者,寫入太多的cookie會造成數據管理的不可控,所以建議儘量少寫cookie,像網易、新浪這些大型互聯網公司,如果觀察一下他們的站點,你會發覺他們會在瀏覽器寫下大量的cookie,不過他們內部一般會有一套嚴格的cookie寫入和清理的管理規定.
cookie有兩個很重要的屬性:domain和path 
domain告訴瀏覽器當前要添加的cookie的域名歸屬,如果沒有明確指明則默認爲當前域名,比如通過訪問www.vinceruan.info添加的cookie的域名默認就是www.vinceruan.info,通過訪問blog.vinceruan.info所生成的cookie的域名就是blog.vinceruan.info. 
path告訴瀏覽器當前要添加的cookie的路徑歸屬,如果沒有明確指明則默認爲當前路徑,比如通過訪問www.vinceruan.info/java/hotspot.html添加的cookie的默認路徑就是/java/,通過blog.vinceruan.info/java/hotspot.html生成的cookie的路徑也是/java/. 
在清楚domain和path的生成規則後,我們需要知道瀏覽器在什麼時候提交什麼cookie到服務器,即瀏覽器是通過怎樣的規則篩選cookie並提交到服務器的? 
瀏覽器提交的cookie需要滿足以下兩點: 
1.當前域名或者父域名下的cookie 
而且 
2.當前路徑或父路徑下的cookie 
要滿足以上兩個條件的cookie纔會被提交.舉個例子:有4個cookie: 
cookie1:[name=value, domain=.vinceruan.info path=/] 
cookie2:[name=value, domain=blog.vinceruan.info path=/java/] 
cookie3:[name=value, domain=www.vinceruan.info path=/] 
cookie4:[name=value, domain=blog.vinceruan.info path=/] 
當我訪問blog.vinceruan.info時, 
cookie1可以被提交,因爲.vinceruan.info是blog.vinceruan.info的父域名. path路徑也一致. 
cookie2不能被提交,因爲雖然domain是保持一致的,但是path不一致,當前訪問的是/, 但是cookie2的path是/java/ 
cookie3不能被提交,因爲雖然path是一致的,但是 www.vinceruan.info不是blog.vinceruan.info的父域名. 
cookie4可以被提交,因爲domain和cookie都嚴格保持一致. 
這裏需要注意的是, 在瀏覽器看來. www.vinceruan.info不是blog.vinceruan.info的父域名,而vinceruan.info纔是blog.vinceruan.info的父域名, www.vinceruan.info也算是一個二級域名
所以如果我們需要在所有二級域名下共享islogin=1的cookie,用java代碼如下: 
Cookie c = new Cookie("islogin","1"); 
c.setDomain(" .vinceruan.info");//注意是以點號開頭的. 
c.setPath=("/"); 
response.addCookie(c); 
如果要在所有的二級域名下的/java/路徑下共享silogin=1的cookie,用java代碼如下: 
Cookie c = new Cookie("islogin","1"); 
c.setDomain(" .vinceruan.info");//注意是以點號開頭的. 
c.setPath=("/java/"); 
response.addCookie(c); 


現在,我們瞭解下session機制的原理, session都是保存在服務器端的,而http連接是無狀態的,那麼服務器是如何在多次獨立的http連接中爲你維持同一個session呢? 
這依賴於一個叫JSESSIONID的參數,這個參數可以從cookie或url獲得,你如果你打開firebug,同時你的firefox是沒有禁用cookie的,那麼你刷新幾次頁面,你會看到瀏覽器提交的cookie中有一個叫JSESSIONID的key/value,這個就是會話ID,在這裏你可以做一個試驗,我們都知道firefox和IE 的cookie是不共享的,因此你在firefox下登錄了,你用IE打開同一個網址,頁面會顯示你還處在未登錄的狀態,但是如果我在firefox下已經登錄,並且拿到JSESSIONID的值,再到IE中輸入url,並且加入JSESSION=.....的參數,你會發現,IE下也會顯示我已經登錄了。 
這說明,如果我通過網絡截除到了別人的JESSIONID,我就可以在服務器的會話還沒過期前訪問該站,如果對方還是處於登錄狀態的,我就可以修改對方資料甚至密碼,多麼可怕,當然這一切都是理論上的。


session什麼時候被創建
  一個常見的錯誤是以爲session在有客戶端訪問時就被創建,然而事實是直到某server端程序(如Servlet)調用HttpServletRequest.getSession(true)這樣的語句時纔會被創建。
session何時被刪除


session在下列情況下被刪除:
A.程序調用HttpSession.invalidate()
B.距離上一次收到客戶端發送的session id時間間隔超過了session的最大有效時間
C.服務器進程被停止:再次注意關閉瀏覽器只會使存儲在客戶端瀏覽器內存中的session cookie失效,不會使服務器端的session對象失效。 


好了,一切都顯得很順利,要在不同的二級域名共享session,只需要把JESSIONID寫進共享Cookie就行了。有時在進行session共享時,需要先設置session爲無效,否則在設置domain爲父域名時,會匹配不到

這裏需要注意的是:當多個cookie提交到服務器端的時候,如果有多個JSESSIONID也被提交,服務器端會採取嚴格匹配更加優先的原則。

舉個例子,如果我們在訪問www.vinceruan.info新建了一個session的同時, 我寫入一個JSESSIONID=****的、domain是.vinceruan.info的cookie, 理論上blog.vinceruan.info 也可以訪問到在www.vinceruan.info這邊創建的session了,但是,如果我在訪問www.vinceruan.info前先訪問了blog.vinceruan.info, 同時創建了屬於blog.vinceruan.info的session,這是再去訪問www.vinceruan.info站點,同時建立了另一個session,並且建立了共享的JSESSIONID,這時再回去訪問blog.vinceruan.info時,你會看到瀏覽器提交了兩個JSESSIONID的cookie,類似於: 
JSESSIONID=EXAD2AD5FA4D1A5D4 path =/ domain=blog.vinceruan.info 
JSESSIONID=254SD2S5S1D2S5DS5 path = / domain=.vinceruan.info 
可以看出,後者是我手工創建的,而前者是jboss創建的。很遺憾,服務器匹配的是domain=blog.vinceruan.info 的JSESSIONID


                                                                    SSO

1、什麼是單點登錄(single-sign-on)

舉個例子,如果你登錄了msn messenger,訪問hotmail郵件就不用在此登錄。

一般單點登錄都需要有一個獨立的登錄站點,一般具有獨立的域名,專門的進行註冊,登錄,註銷等操作

我們爲了討論方便,把這個登錄站點叫做站點P,設其Urlhttp://passport.yizhu2000.com,需要提供服務的站點設爲AB,跨站點單點登錄是指你在A網站進行登錄後,使用B網站的服務就不需要再登錄

2、單點登錄分類

跨子域單點登錄

完全跨單點登錄

3、單點登錄實現機制

實現SSO的技術主要有:

(1)session同步

(2)基於cookies實現,需要注意如下幾點:如果是基於兩個域名之間傳遞sessionid的方法可能在windows中成立,在unix&linux中可能會出現問題;可以基於數據庫實現;在安全性方面可能會作更多的考慮。另外,關於跨域問題,雖然cookies本身不跨域,但可以利用它實現跨域的SSO

(3) Broker-based(基於經紀人),例如Kerberos等;這種技術的特點就是,有一個集中的認證和用戶帳號管理的服務器。經紀人給被用於進一步請求的電子的身份存取。中央數據庫的使用減少了管理的代價,併爲認證提供一個公共和獨立的"第三方"。例如Kerberos,Sesame,IBM KryptoKnight(憑證庫思想)等。Kerberos是由麻省理工大學發明的安全認證服務,當前版本V5,已經被UNIXWindows作爲默認的安全認證服務集成進操作系統。http://www.ibm.com/developerworks/cn/security/se-sso/

(4) Agent-based(基於代理人)在這種解決方案中,有一個自動地爲不同的應用程序認證用戶身份的代理程序。這個代理程序需要設計有不同的功能。比如,它可以使用口令表或加密密鑰來自動地將認證的負擔從用戶移開。代理人被放在服務器上面,在服務器的認證系統和客戶端認證方法之間充當一個"翻譯"。例如SSH等。

(5) Token-based,例如SecurID,WebID,現在被廣泛使用的口令認證,比如FTP,郵件服務器的登錄認證,這是一種簡單易用的方式,實現一個口令在多種應用當中使用。

(6) 基於網關Agent and Broker-based,這裏不作介紹。

(7) 基於安全斷言標記語言(SAML)實現,SAML(Security Assertion Markup Language,安全斷言標記語言)的出現大大簡化了SSO,並被OASIS批准爲SSO的執行標準。開源組織OpenSAML 實現了 SAML 規範。http://blog.csdn.net/shanyou/article/details/5372233

CAS由耶魯大學開發的單點登錄系統(SSO,single sign-on),應用廣泛,具有獨立於平臺的,易於理解,支持代理功能。

下文主要介紹一種基於http重定向和票據,並以跨域Cookie的共享爲核心的SSO,最後,分析Sohu 完全跨SSO登陸過程(CAS外面包裝了AJAX技術)

4、跨子域單點登錄

所謂跨子域登錄,AB站點和P站點位於同一個域下面,比如A站點爲http://blog.yizhu2000.com     B站點爲 http://forum.yizhu2000.com,他們和登錄站點P的關係可以看到,都是屬於同一個父域,yizhu2000.com,不同的是子域不同,一個爲blog,一個爲forum,一個是passport

我們先看看最常用的非跨站點普通登錄的情況,一般登錄驗證通過後,一般會將你的用戶名和一些用戶信息,通過某一密鑰進行加密,寫在本地,也就是一個加密的cookie,我們把這個cookie叫做--票(ticket)。

需要判斷用戶是否登錄的頁面,需要讀取這個ticket,並從其中解密出用戶信息,如果ticket不存在,或者無法解密,意味着用戶沒有登錄,或者登錄信息不正確,這時就要跳轉到登錄頁面進行登錄,在這裏加密的作用有兩個,一是防止用戶信息被不懷好意者看到,二是保證ticket不會被僞造,後者其實更爲重要,加密後,各個應用需要採用與加密同樣的密鑰進行解密,如果不知道密鑰,就不能僞造出ticket

跨子域的單點登錄,和上述普通登錄的過程沒有什麼不同,唯一不同的是寫cookie時,由於登錄站點P和應用A處於不同的子域,P站寫入的cookie的域爲passport.yizhu2000.net,而A站點爲forum.yizhu2000.netA在判斷用戶登錄時無法讀到P站點的ticket

解決方法非常簡單,當Login完成後P站點寫ticket的時候,只需把cookie的域設爲他們共同的父域yizhu2000.net就可以了:cookie.setDomain(".yizhu2000.net");A站點自然就可以讀到這個ticket

5、完全跨域單點登錄

完全跨域登錄,是指AB站點和P站點沒有共同的父域,比如A站點爲forum.yizhu1999.net,B站點爲blog.yizhu1998.net,大家可以參考微軟旗下的幾個站點http://www.live.comwww.hotmail.com,這兩個站點就沒有共同的父域,而仍然可以共用登錄,怎樣才能實現呢?請參考下圖,由於這種情況ticket比較複雜,我們暫時把P站點創建的的ticket叫做P-ticket,而A站點創建的ticketA-ticketB的爲B-ticket


6、完全跨域單點登錄流程


當用戶訪問A站點上需要登錄才能訪問的資源時,A站點會首先查看是否有A-ticket,如果沒有,證明用戶沒有在A站點登錄過,不過並不保證用戶沒有在B站點登錄,(重複一下,既然是單點登錄,當然無論你在AB任意一個站點登錄過,另外一個站點都要可以訪問,並且,站點Aforum.yizhu1999.com)不能讀取到由站點Ppassport.yizhu2000.com)創建的加密ticket),請求會被重定向到p站點的驗證頁面,驗證頁面讀取P-ticket,如果沒有,或者解密不成功,就需要重定向登錄頁面,登錄頁面完成登錄後,寫一個加密cookie,也就是P-ticket,並且重定向到A站點的登錄處理頁,並把加密的用戶信息作爲參數傳遞給這個頁面,這個頁面接收登錄頁的用戶信息,解密後也要寫一個cookie,也就是A-ticket,今後用戶再次訪問A站點上需要登錄權限才能訪問的資源時,只需要檢查這個A-cookie是否存在就可以了

當用戶訪問B站點時,會重複上面的過程,監測到沒有B-ticket,就會重定向到P站點的驗證頁面,去檢查P-ticket,如果沒有,就登錄,有則返回B的登錄處理頁面寫B-ticket


7、註銷的時候需要刪除P-ticketA-ticket


創建一個和你要刪除的cookie同名的cookie,並把cookieexpire設爲當前時間之前的某個時間,不過在跨子域的刪除cookie時有一點要注意:必須要把cookie的域設置爲父域,在本文中爲yizhu2000.com


                                             Sohu SSO登陸過程分析


Sohu的Passport將focus.cn,17173.com,sogou.com,chinaren.com這四個域名下的產品全部整合在一起了。用戶在這四個站點中任何一個地方都可以登錄。當用戶登錄後可以自由的使用其他域名下的服務。現在很多網站上都有bbs blog album服務。這些服務一般也是自己維護自己的用戶信息。當發展到一定時候,也需要一個Passport機制整合所有服務,使用戶可以單點登錄。


在http://passport.sohu.com/ 登錄後 fiddler可以攔截到如下的返回信息:



由於passport.sohu.com的登錄界面使用了iframe隱藏提交。所以頁面沒有看到刷新。隱藏的iframe把用戶名和加密的password和其他信息發送給了passport.sohu.com。passport.sohu.com在Response中設置了成功登錄的cookie。這個cookie可以證實這個用戶成功登錄了passport.sohu.com




當用戶在Passport成功登錄後。客戶端的Javascript根據成功登錄的標誌,操作iframe請求http://passport.sohu.com/sso/crossdomain_all.jsp?action=login 因爲在同一個域名下,沒有跨域,在這次請求中,上次成功登陸的cookie會被一併帶着回去。服務器端檢查到成功登錄的cookie後會Render回一段同時登錄多個站點的html。




這段html 要向4個地址發送請求。截至到現在都是在相同的Domain(passport.sohu.com)請求和返回,爲真正的跨站點登錄做準備,真正的跨站點登錄還沒有開始。下面passport.sohu.com通過sso/crossdomain.jsp 在服務器端進行Redirect 設置http head 爲302進行跳轉。跳轉後在這個跳轉後的域名下設置登錄成功的cookie。這就是sohu實現跨站點登錄的核心過程。下面是passport.sohu.com登錄17173.com的過程。
1.  通過http://passport.sohu.com/sso/crossdomain_all.jsp?action=login Render回來的script <script type="text/javascript" src="http://passport.sohu.com/sso/crossdomain.jsp?action=login&domain=17173.com"></script> 請求同域下的http://passport.sohu.com/sso/crossdomain.jsp?action=login&domain=17173.com 這時passport.sohu.com下成功登錄的cookie會被帶回去。




2.  服務器看到成功登錄的Cookie後。在服務器端計算出一個加密後的17173.com的登錄Url,並Redirect到這個Url。



3.  17173.com從url的QueryString中取得信息。並在Response中設置Cookie。這個Cookie終於寫到了17173.com下。而不是passport.sohu.com下。從而使得用戶在17173.com下登錄。其實用戶在17173.com下手動登錄也是寫上同樣的Cookie。以後用戶再訪問17173.com的頁面時這個Cookie會被帶回去。這就表示用戶在17173.com下成功登錄過了。




經過上面的步驟。用戶在passport.sohu.com下登錄的同時也在其他站點登錄了。


完全跨域單點登錄實現的核心思想:發送跨域請求,然後各自寫各自的cookie。

具體實現有很多變種,上面sohu的例子只是其中一種,還可以參看京東單點登錄的例子。

同時,爲了保證安全性,建議使用https安全傳輸、綁定IP等


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章