网上看到这篇文章,很喜欢这种分析思路,这里学习记录一下。
最近小了解了下cookie. 以前觉得cookie无非就是一连串键值对, 在深入了解之后发现 远没自己想的那么简单, 自己果真太肤浅了….
好吧, 这里主要探讨一下以下几个问题:
为了获得简单直观的感受, 这里我们使用以下工具进行探索:
好, 假设我们现在有两个域名, 三个网站, 然后利用他们来进行实验
首先我们准备一个简单的html页面:
orz.net
this is orz.net
this is orz.net
this is sub.orz.net
this is coolkid.net
然后准备好两个lua脚本, 一个用于打印cookie(echo_cookie.lua), 一个用于设置cookie(set_cookie.lua):
echo_cookie.lua 打印cookie
function get_cookie(s_cookie)
local cookie = {}
-- string.gfind is renamed to string.gmatch
for item in string.gmatch(s_cookie, "[^;]+") do
local _, _, k, v = string.find(item, "^%s*(%S+)%s*=%s*(%S+)%s*")
if k ~= nil and v~= nil then
cookie[k] = v
end
end
return cookie
end
function print_cookie(cookie)
for k, v in pairs(cookie) do
ngx.say(k .. " : " .. v .. "")
end
end
ngx.header['Content-Type'] = 'text/html'
local raw_cookie = ngx.req.get_headers()["Cookie"]
if raw_cookie == nil then
ngx.say "no cookie found"
else
print_cookie(get_cookie(raw_cookie))
end
设置cookie的代码比较简单, 直接给ngx.header['Set-Cookie']
赋值即可. 之后我们主要就是修改这个文件, 通过修改设置来观察发送Cookie的情况.
接下来准备一下nginx配置文件:
nginx配置文件
# 记得include进来
server {
listen 80;
server_name orz.net sub.orz.net coolkid.net;
access_log "logs/cookie.log";
location / {
root html;
try_files $uri /orz.html;
header_filter_by_lua_file script/set_cookie.lua;
}
location /echo_cookie {
content_by_lua_file script/echo_cookie.lua;
}
}
接着我们改一下hosts文件, 将上述三个网站都指向本地
add hosts
# learn cookie
127.0.0.1 orz.net sub.orz.net coolkid.net
好了, 最后使用浏览器访问下orz.net/orz.html, 看看效果:
开始进行尝试吧;)
一开始我对cookie的观点停留在:
Set-Cookie
头设置cookieCookie
头中好, 接下来我想在orz.net中设置3个键值对, 第一个蹦出来的(错误)想法是:
set_cookie.lua
ngx.header["Set-Cookie"] = "perl=1; python=2; ruby=3"
我们通过chrome看看结果:
response | request after response |
---|---|
结果和预期有很大的出入. 虽然Set-Cookie头设置好了, 但是再次请求时仅仅设置了头一个变量, 剩下的两个均被丢弃了. 好吧, 遇到这种情况说明自己以前的观点是错误的, 那我们就从定义开始学习呗, 细心读一下wiki
仔细读了一下, 了解到一个Set-Cookie只能设置一个键值对. 好, 我们改一下set_cookie.lua的代码, 让它设置多个Set-Cookie头:
set-cookie.lua
ngx.header['Set-Cookie'] = {
"perl=1",
"python=2"
}
再次访问, 我们得到了想要的结果.
注意到cookie只在当前域名下生效. 这里就牵扯到cookie的属性设置了
If not specified, they default to the domain and path of the object that was requested.
我们再改一下代码, 让部分cookie可以在其他域名生效:
set_cookie.lua
ngx.header['Set-Cookie'] = {
"perl=1",
"python=2; domain=.orz.net; path=/",
"ruby=3; domain=coolkid.net; path=/"
}
看下结果:
到了这里, 我似乎明白点了什么:
当然, 有关跨域共享cookie的问题网上有很多讨论, 例如利用js向第三方域发送cookie. 当然如果有人在网站上插一段类似代码, 就可以对cookie进行截获. 通过使用属性HttpOnly
即可避免.
最后再提一点: 默认设置的cookie都是在关闭浏览器后失效的.
网上讨论这个也有很多, 但个人觉得没有一个讲得特别清楚….
从我个人理解出发: 一个cookie从属于一个域. 当访问这个域的时候就会发送相应的cookie. 好, 假设一个网站包含了一个第三方的image(例如taobao的图片), 当我们用浏览器访问这个网站的 时候, 浏览器会自动请求这个第三方的图片, 如果这个请求返回的结果中带了相应的Set-Cookie, 那么浏览器就设置了这个第三方的cookie. 相对你访问的目标网站, 这个第三方设置的cookie即为 第三方cookie.
个人比较推荐禁止第三方cookie.
有关cookie的其他信息, 例如安全性等, 还是强烈推荐阅读wiki