Cookie & Session
Cookie
Cookie解决的问题
Cookie的出现是为了解决http无状态的问题,如何做到维护http请求的状态。
Cookie的实现
简单地说,cookie 就是浏览器储存在用户电脑(手机)上的一小段文本文件。cookie 是纯文本格式,不包含任何可执行的代码,因此cookie本身是没有危害性的。
实现也是相当的简单,端上访问服务器,服务端在返回页面的同时,会带上cookie;端上在收到这些cookie信息后就在浏览器上种下cookie;在后续的发送请求是,再将这个cookie带上,给到服务端。
Cookie的进一步细分
- Session Cookie:这种的cookie的生命周期是当前会话,当关闭浏览器的时候,所存的cookie即被清楚。创建方式:在创建cookie不设置Expires即可。
- Persistent Cookie:持久化的cookie,是在创建的时候,设置了过期时间的。
- Secure cookie:安全cookie,由于cookie在客户端是明文保存的,也是明文传输的,而这种方式就保证了cookie的安全性。这种cookie是在https访问下的cookie形态,以确保cookie在从客户端传递到Server的过程中始终加密的。
- HttpOnly Cookie:默认的cookie是可以通过js进行设置修改的,设置成HttpOnly就控制了js无法设置cookie了(其实这句话是错误的,js还是可以设置修改cookie,但是已经没有意义了,设置的cookie不会被传到服务端,只有原来的httponly值会传送到服务器,所有可以理解成js无法设置),从而避免了跨站攻击时JS偷取cookie的情况。
- SameSite cookie:每个网页可能会访问第三方的网站的资源,在访问第三方网站资源的时候,也是会将cookie信息带到第三方网站的,这就存在CSRF(跨站请求伪造)攻击,在伪造的第一方网站上放入第三方网站的链接,从而获得进入这个第三方网站的cookie。所以有了SameSite cookie的机制,保证在访问第三方站点的时候,不带上cookie,它有两个值:Strict 和 Lax。
- Super Cookie:超级cookie是设置公共域名前缀上的cookie。通常a.b.com的cookie可以设置在a.b.com和b.com,而不允许设置在.com上,但是很不幸的是历史上一些老版本的浏览器因为对新增后缀过滤不足导致过超级cookie的产生。
- Zombie Cookie:僵尸cookie是指那些删不掉的,删掉会自动重建的cookie。僵尸cookie是依赖于其他的本地存储方法,例如flash的share object,html5的local storages等,当用户删除cookie后,自动从其他本地存储里读取出cookie的备份,并重新种植。
Cookie的设置
格式
Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure]
domain
指定了cookie将要被发送至哪个或哪些域的请求中。
path
这个属性是和domain属性的概念地一样的,但是控制的粒度更细了些。指定了请求的资源 URL 中必须存在指定的路径时,才会发送Cookie 消息头。
path的匹配是将 path 选项的值与请求的 URL 从头开始逐字符比较完成的。
需要注意的是,只有在 domain 选项核实完毕之后才会对 path 属性进行比较。
secure
该选项只是一个标记而没有值。只有当一个请求通过 SSL 或 HTTPS 创建时,包含 secure 选项的 cookie 才能被发送至服务器。这种 cookie 的内容具有很高的价值,如果以纯文本形式传递很有可能被篡改。
事实上,机密且敏感的信息绝不应该在 cookie 中存储或传输,因为 cookie 的整个机制原本都是不安全的。默认情况下,在 HTTPS 链接上传输的 cookie 都会被自动添加上 secure 选项。
expire
指定了 cookie 何时不会再被发送至服务器,随后浏览器将删除该 cookie。
没有设置expires属性,cookie 的生命周期仅限于当前会话中,关闭浏览器意味着这次会话的结束,所以会话 cookie 仅存在于浏览器打开状态之下。
cookie删除机制
- 会话 cooke (Session cookie) 在会话结束时(浏览器关闭)会被删除
- 持久化 cookie(Persistent cookie)在到达失效日期时会被删除
- 如果浏览器中的 cookie 数量达到限制,那么 cookie 会被删除以为新建的 cookie 创建空间。
JavaScript 中的 cookie
在 JavaScript 中通过 document.cookie 属性,你可以创建、维护和删除 cookie。
设置:
document.cookie="name=Nicholas;domain=nczonline.net;path=/";
通过访问 document.cookie 返回的 cookie 遵循发向服务器的 cookie 一样的访问规则。要通过 JavaScript 访问 cookie,该页面和 cookie 必须在相同的域中,有相同的 path,有相同的安全级别。
Cookie的限制与缺陷
- cookie 的属性
- cookie 的总大小
每个域名下不超过20个cookie,总的cookie大小不能超过4KB。所有超出该限制的 cookie 都会被截掉并且不会发送至服务器。
缺陷:每次请求都要带上,增大网络堵塞;本地可修改
Cookie的可取代方案
JSON Web Tokens
JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。
一个JWT实际上就是一个字符串,它由三部分组成,头部(header)、载荷(payload)与签名。
base = base64(header).base64(payload)
jwt = base.sign()
JWT是不安全的,不应该传递隐私信息。
window.name
IP address
URL (query string)
Hidden form fields
ETag
Session
Cookie是http状态的客户端解决方案,而Session是服务端解决方案。它通过服务端来保持请求的状态。
在创建了Session的同时,服务器会为该Session生成唯一的Session id,而这个Session id在随后的请求中会被用来重新获得已经创建的Session;在Session被创建之后,就可以调用Session相关的方法往Session中增加内容了,而这些内容只会保存在服务器中,发到客户端的只有Session id;当客户端再次发送请求的时候,会将这个Session id带上,服务器接受到请求之后就会依据Session id找到相应的Session,从而再次使用之。正式这样一个过程,用户的状态也就得以保持了。
Session与Cookie的关系
cookie和session的方案虽然分别属于客户端和服务端,但是服务端的session的实现对客户端的cookie有依赖关系的,服务端执行session机制时候会生成session的id值,这个id值会发送给客户端,客户端每次请求都会把这个id值放到http请求的头部发送给服务端,而这个id值在客户端会保存下来,保存的容器就是cookie,因此当我们完全禁掉浏览器的cookie的时候,服务端的session也会不能正常使用。
Session的生命周期和有效期
Session保存在服务器端。为了获得更高的存取速度,服务器一般把Session放在内存里。每个用户都会有一个独立的Session。如果Session内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session里的信息应该尽量精简。
Session在用户第一次访问服务器的时候自动创建。Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session“活跃(active)”了一次。
由于会有越来越多的用户访问服务器,因此Session也会越来越多。为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。
Session的问题
- Session的存储耗费了服务端的内存,所以这个是一个问题
- 现在的服务端是多机器负载均衡,某台机器上的存储的Session无法在另一台机器上被知晓,这就需要有Session同步问题。