Go 的cookies介紹

cookies

  • 定義
type Cookie struct {
        Name  string
        Value string
        Path       string
        Domain     string
        Expires    time.Time 
        RawExpires string 
        MaxAge   int
        Secure   bool
        HttpOnly bool
        SameSite SameSite
        Raw      string
        Unparsed []string
}
  • 範例
package main
import (
    "encoding/json"
    "flag"
    "net/http"
)
var (
    addr = flag.String("addr", ":8080", "server address")
)
func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", index)
    mux.HandleFunc("/get", getCookie)
    mux.HandleFunc("/delete", deleteCookie)
    mux.HandleFunc("/set", setCookie)
    http.ListenAndServe(*addr, mux)
}
func index(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte(`<a href="#" onclick="alert(document.cookie)">Click here!</a>`))
}
func getCookie(w http.ResponseWriter, r *http.Request) {
    c, err := r.Cookie("this_is_a_test_cookie")
    if err != nil {
        w.Write([]byte("读取cookie失败: " + err.Error()))
    } else {
        data, _ := json.MarshalIndent(c, "", "\t")
        w.Write([]byte("读取的cookie值: \n" + string(data)))
    }
}
func deleteCookie(w http.ResponseWriter, r *http.Request) {
    c := http.Cookie{
        Name:   "this_is_a_test_cookie",
        MaxAge: -1}
    http.SetCookie(w, &c)
    w.Write([]byte("cookie已被删除"))
}
func setCookie(w http.ResponseWriter, r *http.Request) {
    c := http.Cookie{
        Name:     "this_is_a_test_cookie",
        Value:    "true",
        HttpOnly: true,
        //Secure:   true,
        MaxAge: 300}
    http.SetCookie(w, &c)
    w.Write([]byte("cookie已创建\n"))
}
  • 缺陷
Cookie会被附加在每个HTTP请求中,所以无形中增加了流量。
由于在HTTP请求中的Cookie是明文传递的,很容易遭受到中间人的攻击,所以安全性成问题,除非用HTTPS。
Cookie的大小限制在4KB左右,对于复杂的存储需求来说是不够用的。
不同的浏览器Cookie不是共享的,你在Chrome中登录了一个网站,使用Firefox还需要再次登录,因为这两个浏览器的Cookie不共享。
同一台机器同一个浏览器会共享同一个Cookie池,A用完浏览器后,如果不清理Cookie, B使用的时候会得到A的Cookie。
Cookie存在本地是明文访问的,其他用户如果能访问的这个Cookie,就能看到这个Cookie的内容
容易遭受XSS跨站访问
第三方脚本追踪。网站中嵌入第三方的代码,就容易被第三方公司利用,在一些互联网巨头和广告公司中经常会使用。你在A网站浏览一些商品,在浏览B网站的时候,B网站的广告会给你推送这些类似商品的信息,这是因为A和B都嵌入了同一个第三方公司的代码,通过Cookie能追踪到你的浏览记录。
Cookie投毒攻击,例如在一个购物网站的Cookie中包含了顾客应付的款项,攻击者将该值改小,达到少付款的目的。

使用Cookie候,需要额外的措施,避免受到攻擊,下面是一些推荐設定:

设置合理的domain和path
设置合适的MaxAge, 不使用时或者推出时设置为-1
设置HttpOnly为true
设置SameSite
采用https, 设置Secure为true
cookie不存储私密的东西,名称不设置直观易读的名称
cookie进行加盐和加密
不设置太大的Cookie
设置到安全较高的操作时,服务器端对cookie和客户端ID(浏览器属性、操作系统、客户端IP)进行验证,避免被人窃取cookie

securecookie

// Hash keys should be at least 32 bytes long
var hashKey = []byte("very-secret")
// Block keys should be 16 bytes (AES-128) or 32 bytes (AES-256) long.
// Shorter keys may weaken the encryption used.
var blockKey = []byte("a-lot-secret")
var s = securecookie.New(hashKey, blockKey)
func SetCookieHandler(w http.ResponseWriter, r *http.Request) {
    value := map[string]string{
        "foo": "bar",
    }
    if encoded, err := s.Encode("cookie-name", value); err == nil {
        cookie := &http.Cookie{
            Name:  "cookie-name",
            Value: encoded,
            Path:  "/",
            Secure: true,
            HttpOnly: true,
        }
        http.SetCookie(w, cookie)
    }
}
func ReadCookieHandler(w http.ResponseWriter, r *http.Request) {
    if cookie, err := r.Cookie("cookie-name"); err == nil {
        value := make(map[string]string)
        if err = s2.Decode("cookie-name", cookie.Value, &value); err == nil {
            fmt.Fprintf(w, "The value of foo is %q", value["foo"])
        }
    }
}