Cookie和Session是为了在无状态的HTTP协议之上维护会话状态,使得服务器可以知道当前是和哪个客户在打交道。本文来详细讨论Cookie和Session的实现机制,以及其中涉及的安全问题。
因为HTTP协议是无状态的,即每次用户请求到达服务器时,HTTP服务器并不知道这个用户是谁、是否登录过等。现在的服务器之所以知道我们是否已经登录,是因为服务器在登录时设置了浏览器的Cookie!Session则是借由Cookie而实现的更高层的服务器与浏览器之间的会话。
一、cookie安全隐患
Cookie提供了一种手段使得HTTP请求可以附加当前状态, 现今的网站也是靠Cookie来标识用户的登录状态的:
- 用户提交用户名和密码的表单,这通常是一个POST HTTP请求。
- 服务器验证用户名与密码,如果合法则返回200(OK)并设置 Set-Cookie 为 authed=true 。
- 浏览器存储该Cookie。
- 浏览器发送请求时,设置
Cookie
字段为 authed=true 。 - 服务器收到第二次请求,从
Cookie
字段得知该用户已经登录。 按照已登录用户的权限来处理此次请求。
这里面的问题在哪里?
我们知道可以发送HTTP请求的不只是浏览器,很多HTTP客户端软件(包括curl、Node.js)都可以发送任意的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存储在服务器端。
-------------------------------------------------------------------------------------------
本文转载自:http://harttle.land/2015/08/10/cookie-session.html