Cookie的机制与安全
什么是Cookie?
HTTP Cookie(也叫Web Cookie或浏览器Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。
cookie,指网站为了辨别用户身份而储存在用户本地终端上的数据。cookie 本质上是 HTTP 的一个内容(请求头)。
在前端工作中,可以这么理解 cookie:
- cookie 是浏览器访问服务器后,服务器传给客户端的一段数据。
- 浏览器将 cookie 保存下来,一般情况下不会删除。
- 浏览器每次访问返回 cookie 的服务器时,都会在请求头(请求的第二部分)中带入这段 cookie
Cookie的作用
- 会话状态管理(如用户登录状态,购物车,游戏分数或者其它需要)
- 个性化设置(用户自定义设置,主题)
- 浏览器行为跟踪(跟踪分析用户行为)
Cookie在浏览器和服务器之间的交流过程
接下来,以client指代客户端,server指代服务端,说明一个 cookie 的整个作用机制:
- 产生cookie:client第一次访问server,server 在响应头中设置一个 cookie 返回给 client,cookie 的内容为要保存的数据。
- 保存 cookie:client 在接收到 server 返回的 cookie 后,将 cookie 保存下来,并给cookie一个有效期,过了有效期,cookie 就会失效。
- 传递 cookie:client 再次访问 server 将会在请求头中带上保存的 cookie,将 cookie 传递到 server。
- 解析 cookie:server 得到 client 传递的 cookie 之后,会解析 cookie,然后将相应的信息返回给 client。在 cookie 没有失效之前,cookie 的使用都是围绕2,3,4三部分来进行的,第1步一般只需要进行一次。
Cookie存在的问题
- cookie 基于浏览器本地存储数据,因此,只有在保存了 cookie 的那个浏览器上能够使用该 cookie。同一设备不同浏览器之间,cookie 不通用。
- cookie 的存储大小有限制: 4KB 左右。
- cookie 存在C盘的一个文件中,不同浏览器存储路劲不一样。
- cookie 是可以被用户手动修改的。
- cookie 的有效期:默认有效期20分钟左右。可以通过后端强制设置有效期,如自动登录时间。
- cookie 的同源策略:cookie 同样也有同源策略,不过与 ajax 略微不用。ajax 需要完全同源,而 cookie 只需要同一父级域名即可。 比如: 请求 qq.com 下的资源时,会带上 qq.com 对应的 cookie,不会带上 baidu.com 的 cookie; 请求 v.qq.com 下的资源时,浏览器不仅会带上 v.qq.com 的 cookie,还会带上 qq.com 的cookie。在这里,qq.com 就是 v.qq.com 的父级域名。
需要特别注意的一点是:在浏览器的认知中,www.qq.com和qq.com是两个不同的域名。因此,www.qq.com 不是 v.qq.com 的父域名,qq.com才是。
由于 cookie 是明文保存在客户端的数据,可能会被客户端修改,存在信息泄露的风险,所以,需要一种比 cookie 更加安全的存储方式来存储数据。session 就是解决安全问题的方法。
Cookie: HttpOnly
标记为HttpOnly的Cookie不能被JavaScript脚本调用,跨站脚本攻击 (XSS) 常常使用 JavaScript 的 document.cookie
API 窃取用户的 Cookie 信息,因此使用 HttpOnly 标记可以在一定程度上避免 XSS 攻击。
Cookie的安全隐患
Cookie提供了一种手段使得HTTP请求附加当前的状态,网站也是靠Cookie标识用户登录状态的:
- 用户提交用户名和密码的表单,通常是一个POST HTTP请求。
- 服务器验证用户名与密码,如果合法则返回200(OK)并设置
Set-Cookie
为authed=true
。 - 浏览器存储该Cookie。
- 浏览器发送请求时,设置
Cookie
字段为authed=true
。 - 服务器收到第二次请求,从
Cookie
字段得知该用户已经登录。 按照已登录用户的权限来处理此次请求。
但是不仅浏览器可以发送HTTP请求,许多HTTP客户端软件也可以发送,可以设置任何头字段,假如我们直接设置Cookie
字段为authed=true
并发送该HTTP请求, 服务器岂不是被欺骗了?这种攻击非常容易,Cookie是可以被篡改的!
Cookie的防篡改机制
服务器可以为每个Cookie项生成签名,由于用户篡改Cookie后无法生成对应的签名, 服务器便可以得知用户对Cookie进行了篡改。一个简单的校验过程可能是这样的:
- 在服务器中配置一个不为人知的字符串(我们叫它Secret),比如:
x$sfz32
。 - 当服务器需要设置Cookie时(比如
authed=false
),不仅设置authed
的值为false
, 在值的后面进一步设置一个签名,最终设置的Cookie是authed=false|6hTiBl7lVpd1P
。 - 签名
6hTiBl7lVpd1P
是这样生成的:Hash('x$sfz32'+'false')
。 要设置的值与Secret相加再取哈希。 - 用户收到HTTP响应并发现头字段
Set-Cookie: authed=false|6hTiBl7lVpd1P
。 - 用户在发送HTTP请求时,篡改了
authed
值,设置头字段Cookie: authed=true|???
。 因为用户不知道Secret,无法生成签名,只能随便填一个。 - 服务器收到HTTP请求,发现
Cookie: authed=true|???
。服务器开始进行校验:Hash('true'+'x$sfz32')
,便会发现用户提供的签名不正确。
通过给Cookie添加签名,使得服务器得以知道Cookie被篡改。
因为Cookie是明文传输的, 只要服务器设置过一次authed=true|xxxx
我不就知道true
的签名是xxxx
了么, 以后就可以用这个签名来欺骗服务器了。因此Cookie中最好不要放敏感数据。 一般来讲Cookie中只会放一个Session Id,而Session存储在服务器端。
Session的机制和安全
Session的定义
在计算机科学领域来说,尤其是在网络领域,会话(session)是一种持久网络协议,在用户(或用户代理)端和服务器端之间创建关联,从而起到交换数据包的作用机制,session在网络协议(例如telnet或FTP)中是非常重要的部分。
个人理解: session 是一种在服务器端保存数据的机制。服务器通过读取浏览器发送的 cookie 和 服务器端的 session 来交换数据。
不同于 cookie,session保存在服务器端,不同的语言保存方式不一样:
- java,保存于服务器内存中,重启服务器,session 消失
- php,保存于服务器文件中,重启服务器,session 依然存在
- nodejs,保存于服务器内存中,重启服务器,sessino 消失
Session的作用
和Cookie大致相同,但是最大的不同点在于两者实现的安全性和实现方式。
Session的实现
依然将客户端称为 client,服务端成为 server。
1.产生 sessionID:session 是基于 cookie 的一种方案,所以,首先要产生 cookie。client 第一次访问 server,server 生成一个随机数,命名为 sessionID,并将其放在响应头里,以 cookie 的形式返回给 client,client 以处理其他 cookie 的方式处理这段 cookie。大概是这样:cookie:sessionID=135165432165
2.保存 sessionID: server 将要保存的数据保存在相对应的 sessionID 之下,再将 sessionID 保存到服务器端的特定的保存 session 的内存中(如 一个叫 session 的哈希表)
3.使用 session: client 再次访问 server,会带上首次访问时获得的 值为 sessionID 的cookie,server 读取 cookie 中的 sessionID,根据 sessionID 到保存 session 的内存寻找与 sessionID 匹配的数据,若寻找成功就将数据返回给 client。
Session 与 cookie 的区别
- session 在服务器端,cookie 在客户端。
- session 用户无法查看和修改,cookie 用户可以查看修改。
- session 和 cookie 的存储容量不同。
- session 的实现依赖于 sessionID,而 sessionID 又存储在 cookie 上,所以,可以这么说:session 是基于 cookie 实现的一种数据存储方式。
Cookie 与 Session 选择
- Cookie 只能存储 ASCII 码字符串,而 Session 则可以存储任何类型的数据,因此在考虑数据复杂性时首选 Session;
- Cookie 存储在浏览器中,容易被恶意查看。如果非要将一些隐私数据存在 Cookie 中,可以将 Cookie 值进行加密,然后在服务器进行解密;
- 对于大型网站,如果用户所有的信息都存储在 Session 中,那么开销是非常大的,因此不建议将所有的用户信息都存储到 Session 中。
参考文献
《图解HTTP》 日 上野宣