Files
build-web-application-with-…/zh-tw/06.1.md
2019-02-26 01:40:54 +08:00

7.7 KiB
Raw Blame History

6.1 session和cookie

session和cookie是網站瀏覽中較為常見的兩個概念也是比較難以辨析的兩個概念但它們在瀏覽需要認證的服務頁面以及頁面統計中卻相當關鍵。我們先來了解一下session和cookie怎麼來的考慮這樣一個問題

如何抓取一個訪問受限的網頁?如新浪微博好友的主頁,個人微博頁面等。

顯然,透過瀏覽器,我們可以手動輸入使用者名稱和密碼來訪問頁面,而所謂的“抓取”,其實就是使用程式來模擬完成同樣的工作,因此我們需要了解“登入”過程中到底發生了什麼。

當用戶來到微博登入頁面輸入使用者名稱和密碼之後點選“登入”後瀏覽器將認證資訊POST給遠端的伺服器伺服器執行驗證邏輯如果驗證透過則瀏覽器會跳轉到登入使用者的微博首頁在登入成功後伺服器如何驗證我們對其他受限制頁面的訪問呢因為HTTP協議是無狀態的所以很顯然伺服器不可能知道我們已經在上一次的HTTP請求中通過了驗證。當然最簡單的解決方案就是所有的請求裡面都帶上使用者名稱和密碼這樣雖然可行但大大加重了伺服器的負擔對於每個request都需要到資料庫驗證也大大降低了使用者體驗(每個頁面都需要重新輸入使用者名稱密碼,每個頁面都帶有登入表單)。既然直接在請求中帶上使用者名稱與密碼不可行那麼就只有在伺服器或客戶端儲存一些類似的可以代表身份的資訊了所以就有了cookie與session。

cookie簡而言之就是在本地計算機儲存一些使用者操作的歷史資訊當然包括登入資訊並在使用者再次訪問該站點時瀏覽器透過HTTP協議將本地cookie內容傳送給伺服器從而完成驗證或繼續上一步操作。

圖6.1 cookie的原理圖

session簡而言之就是在伺服器上儲存使用者操作的歷史資訊。伺服器使用session id來標識sessionsession id由伺服器負責產生保證隨機性與唯一性相當於一個隨機金鑰避免在握手或傳輸中暴露使用者真實密碼。但該方式下仍然需要將傳送請求的客戶端與session進行對應所以可以藉助cookie機制來取得客戶端的標識即session id也可以透過GET方式將id提交給伺服器。

圖6.2 session的原理圖

Cookie是由瀏覽器維持的儲存在客戶端的一小段文字資訊伴隨著使用者請求和頁面在Web伺服器和瀏覽器之間傳遞。使用者每次訪問站點時Web應用程式都可以讀取cookie包含的資訊。瀏覽器設定裡面有cookie隱私資料選項開啟它可以看到很多已訪問網站的cookies如下圖所示

圖6.3 瀏覽器端儲存的cookie資訊

cookie是有時間限制的根據生命期不同分成兩種會話cookie和持久cookie

如果不設定過期時間則表示這個cookie的生命週期為從建立到瀏覽器關閉為止只要關閉瀏覽器視窗cookie就消失了。這種生命期為瀏覽會話期的cookie被稱為會話cookie。會話cookie一般不儲存在硬碟上而是儲存在記憶體裡。

如果設定了過期時間(setMaxAge(606024))瀏覽器就會把cookie儲存到硬碟上關閉後再次開啟瀏覽器這些cookie依然有效直到超過設定的過期時間。儲存在硬碟上的cookie可以在不同的瀏覽器程序間共享比如兩個IE視窗。而對於儲存在記憶體的cookie不同的瀏覽器有不同的處理方式。   

Go設定cookie

Go語言中透過net/http套件中的SetCookie來設定


http.SetCookie(w ResponseWriter, cookie *Cookie)

w表示需要寫入的responsecookie是一個struct讓我們來看一下cookie物件是怎麼樣的


type Cookie struct {
	Name       string
	Value      string
	Path       string
	Domain     string
	Expires    time.Time
	RawExpires string

// MaxAge=0 means no 'Max-Age' attribute specified.
// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
// MaxAge>0 means Max-Age attribute present and given in seconds
	MaxAge   int
	Secure   bool
	HttpOnly bool
	Raw      string
	Unparsed []string // Raw text of unparsed attribute-value pairs
}

我們來看一個例子如何設定cookie


expiration := time.Now()
expiration = expiration.AddDate(1, 0, 0)
cookie := http.Cookie{Name: "username", Value: "astaxie", Expires: expiration}
http.SetCookie(w, &cookie)

  

Go讀取cookie

上面的例子示範瞭如何設定cookie資料我們這裡來示範一下如何讀取cookie


cookie, _ := r.Cookie("username")
fmt.Fprint(w, cookie)

還有另外一種讀取方式


for _, cookie := range r.Cookies() {
	fmt.Fprint(w, cookie.Name)
}

可以看到透過request取得cookie非常方便。

session

session中文經常翻譯為會話其本來的含義是指有始有終的一系列動作/訊息比如打電話是從拿起電話撥號到結束通話電話這中間的一系列過程可以稱之為一個session。然而當session一詞與網路協議相關聯時它又往往隱含了“連線導向”和/或“保持狀態”這樣兩個含義。

session在Web開發環境下的語義又有了新的擴充套件它的含義是指一類別用來在客戶端與伺服器端之間保持狀態的解決方案。有時候Session也用來指這種解決方案的儲存結構。

session機制是一種伺服器端的機制伺服器使用一種類似於散列表的結構(也可能就是使用散列表)來儲存資訊。

但程式需要為某個客戶端的請求建立一個session的時候伺服器首先檢查這個客戶端的請求裡是否包含了一個session標識稱為session id如果已經包含一個session id則說明以前已經為此客戶建立過session伺服器就按照session id把這個session檢索出來使用(如果檢索不到可能會新建一個這種情況可能出現在伺服器端已經刪除了該使用者對應的session物件但使用者人為地在請求的URL後面附加上一個JSESSION的引數)。如果客戶請求不包含session id則為此客戶建立一個session並且同時產生一個與此session相關聯的session id這個session id將在本次響應中返回給客戶端儲存。

session機制本身並不複雜然而其實現和配置上的靈活性卻使得具體情況複雜多變。這也要求我們不能把僅僅某一次的經驗或者某一個瀏覽器伺服器的經驗當作普遍適用的。

小結

如上文所述session和cookie的目的相同都是為了克服http協議無狀態的缺陷但完成的方法不同。session透過cookie在客戶端儲存session id而將使用者的其他會話訊息儲存在伺服器端的session物件中與此相對的cookie需要將所有資訊都儲存在客戶端。因此cookie存在著一定的安全隱患例如本地cookie中儲存的使用者名稱密碼被破譯或cookie被其他網站收集例如1. appA主動設定域B cookie讓域B cookie取得2. XSS在appA上透過javascript取得document.cookie並傳遞給自己的appB

透過上面的一些簡單介紹我們瞭解了cookie和session的一些基礎知識知道他們之間的聯絡和區別做web開發之前有必要將一些必要知識瞭解清楚才不會在用到時捉襟見肘或是在調bug時如無頭蒼蠅亂轉。接下來的幾小節我們將詳細介紹session相關的知識。