Go語言中如何確保Cookie資料的安全傳輸
什麼是Cookie
Cookie(也叫Web Cookie或瀏覽器Cookie)是伺服器傳送到使用者瀏覽器並儲存在本地的一小塊資料,它會在瀏覽器下次向同一伺服器再發起請求時被攜帶併發送到伺服器上。通常,它用於告知服務端兩個請求是否來自同一瀏覽器,如保持使用者的登入狀態。Cookie使基於無狀態的HTTP協議記錄穩定的狀態資訊成為了可能。
Cookie主要用於以下三個方面:
- 會話狀態管理(如使用者登入狀態、購物車、遊戲分數或其它需要記錄的資訊)
- 個性化設定(如使用者自定義設定、主題等)
- 瀏覽器行為跟蹤(如跟蹤分析使用者行為等)
Go語言如何表示Cookie
在Go的net/http庫中使用http.Cookie結構體表示一個Cookie資料,呼叫http.SetCookie函式則會告訴終端使用者的瀏覽器把給定的http.Cookie值設定到瀏覽器Cookie裡,類似下面:
func someHandler(w http.ResponseWriter,r *http.Request) { c := http.Cookie{ Name: "UserName",Value: "Casey",} http.SetCookie(w,&c) }
http.Cookie結構體型別的定義如下:
type Cookie struct { Name string Value string Path string // optional Domain string // optional Expires time.Time // optional RawExpires string // for reading cookies only // 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 SameSite SameSite Raw string Unparsed []string // Raw text of unparsed attribute-value pairs }
Name和Value欄位就不多說了,單獨針對幾個需要解釋的欄位進行說明。
Domain
預設值是當前正在訪問的Host的域名,假設我們現在正在訪問的是www.example.com,如果需要其他子域名也能夠訪問到正在設定的Cookie值的話,將它設定為example.com 。注意,只有正在被設定的Cookie需要被其他子域名的服務訪問到時才這麼設定。
c := Cookie{ ...... Domain: "example.com",}
Path
設定當前的 Cookie 值只有在訪問指定路徑時才能被伺服器程式讀取。預設為服務端應用程式上的任何路徑,但是您可以使用它限制為特定的子目錄。例如:
c := Cookie{ Path: "/app/",}
Secure
標記為Secure 的Cookie只應通過被HTTPS協議加密過的請求傳送給服務端。但即便設定了 Secure 標記,敏感資訊也不應該通過Cookie傳輸,因為Cookie有其固有的不安全性,Secure 標記也無法提供確實的安全保障。從 Chrome 52 和 Firefox 52 開始,不安全的站點(http:)無法使用Cookie的 Secure 標記。
HttpOnly
為避免跨域指令碼 (XSS) 攻擊,通過JavaScript的API無法訪問帶有 HttpOnly 標記的Cookie,它們只應該傳送給服務端。如果包含服務端Session 資訊的Cookie 不想被客戶端JavaScript 指令碼呼叫,那麼就應該為其設定 HttpOnly 標記。
安全地傳輸Cookie
接下來我們探討兩種安全傳輸Cookie的方法
對Cookie資料進行數字簽名
對資料進行數字簽名是在資料上新增“簽名”的行為,以便可以驗證其真實性。不需要對資料進行加密或遮蔽。
簽名的工作方式是通過雜湊-我們對資料進行雜湊,然後將資料與資料雜湊一起儲存在Cookie中。然後,當用戶將Cookie傳送給我們時,我們再次對資料進行雜湊處理,並驗證其是否與我們建立的原始雜湊匹配。
我們不希望使用者也用篡改後的資料建立新的雜湊,因此經常會看到使用HMAC之類的雜湊演算法,以便可以使用金鑰對資料進行雜湊。這樣可以防止終端使用者同時編輯資料和數字簽名(雜湊)。
JWT也是使用的這種數字簽名的方式進行傳輸的。
上面的資料簽名過程並不需要我們自己去實現,我們可以在Go中使用gorilla/securecookie的程式包來完成此操作,在該程式包中,你可以在建立SecureCookie時為其提供雜湊金鑰,然後使用該物件來保護你的Cookie。
對Cookie資料進行簽名:
//var s = securecookie.New(hashKey,blockKey) var hashKey = securecookie.GenerateRandomKey(64) var s = securecookie.New(hashKey,nil) func SetCookieHandler(w http.ResponseWriter,r *http.Request) { encoded,err := s.Encode("cookie-name","cookie-value") if err == nil { cookie := &http.Cookie{ Name: "cookie-name",Value: encoded,Path: "/",} http.SetCookie(w,cookie) fmt.Fprintln(w,encoded) }
解析被簽名的 Cookie:
func ReadCookieHandler(w http.ResponseWriter,r *http.Request) { if cookie,err := r.Cookie("cookie-name"); err == nil { var value string if err = s.Decode("cookie-name",cookie.Value,&value); err == nil { fmt.Fprintln(w,value) } } }
注意這裡的Cookie資料未加密,僅僅是被編碼了,任何人都可以把Cookie資料解碼回來。
加密Cookie 資料
每當將資料儲存在Cookie中時,請始終儘量減少儲存在Cookie中的敏感資料量。不要儲存使用者密碼之類的東西,並確保任何編碼資料也沒有此資訊。在某些情況下,開發人員在不知不覺中將敏感資料儲存在Cookie或JWT中,因為它們是base64編碼的,但實際上任何人都可以解碼該資料。它已編碼,未加密。
這是一個很大的錯誤,因此,如果你擔心意外儲存敏感內容,建議 你使用gorilla/securecookie之類的軟體包。
之前我們討論瞭如何將其用於對Cookie進行數字簽名,但是securecookie也可以用於加密和解密Cookie資料,以使其無法輕鬆解碼和讀取。
要使用該軟體包加密Cookie,只需在建立SecureCookie例項時傳入一個blockKey即可。
將上面簽名Cookie的程式碼片段進行一些小改動,其他地方完全不用動,securecookie包會幫助我們進行Cookie的加密和解密:
var hashKey = securecookie.GenerateRandomKey(64) var blockKey = securecookie.GenerateRandomKey(32) var s = securecookie.New(hashKey,blockKey)
總結
今天的文章除了闡述如何使用Go語言安全地傳輸Cookie資料外,再次格外強調一遍,編碼和加密的不同,從資料可讀性上看,兩者差不多,但本質上是完全不一樣的:
- 編碼使用公開可用的方案將資料轉換為另一種格式,以便可以輕鬆地將其反轉。
- 加密將資料轉換為另一種格式,使得只有特定的個人才能逆轉轉換。
我們在做資料傳輸時一定要記住兩者的區別,某種意義上,我覺得記住這兩點的區別比你學會今天文章裡怎麼安全傳輸Cookie更重要。
到此這篇關於Go語言中如何確保Cookie資料的安全傳輸的文章就介紹到這了,更多相關Go Cookie資料傳輸內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!