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属性
是否仅用于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
Domain string
Expires time.Time
RawExpires string
MaxAge int
Secure bool
HttpOnly bool
SameSite SameSite
Raw string
Unparsed []string
}
查看net/http定义的函数,可以发现读Cookie实现是读取Request.Header里面的Cookie header;而修改Cookie就设置ResponseWriter.Header()里面的Set-Cookie header,例如setcookie。
Example
操作cookie
cookie := http.Cookie{Name: "testcookiename", Value: "testcookievalue", Path: "/", MaxAge: 86400}
http.SetCookie(w, &cookie)
cookie, err := req.Cookie("testcookiename")
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函数实现:
func SetCookie(w ResponseWriter, cookie *Cookie) {
if v := cookie.String(); v != "" {
w.Header().Add("Set-Cookie", v)
}
}
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信息操作。
CSRF
cookie是CSRF两种基本触发条件之一。