cookie、session和token的介绍

为什么会有cookie和session

因为HTTP是无状态协议

无状态的意思是:HTTP协议不具备保存之前发送过的请求或响应的功能。每次的请求是相互独立的,第n次的请求结果和第n-1次、第n+1次的请求结果不会互相影响。于是cookie和session就被用于解决HTTP无状态的问题。

会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。

Cookie机制

Cookie技术是客户端的解决方案,Cookie就是由服务器发给客户端的特殊信息,而这些信息以文本文件的方式存放在客户端,然后客户端每次向服务器发送请求的时候都会带上这些特殊的信息。

让我们说得更具体一些:

  • 当用户使用浏览器访问一个支持Cookie的网站的时候,用户会提供包括用户名在内的个人信息并且提交至服务器;
  • 接着,服务器在向客户端回传相应的超文本的同时也会发回这些个人信息,当然这些信息并不是存放在HTTP响应体(Response Body)中的,而是存放于HTTP响应头(Response Header);
  • 当客户端浏览器接收到来自服务器的响应之后,不同的浏览器采用不同的方式保存Cookie,对于Windows操作系统而言,IE浏览器可以从: C:\Documents and Settings\[用户名]\Cookies目录中找到存储的Cookie;
  • 自此,客户端再向服务器发送请求的时候,都会把相应的Cookie再次发回至服务器。而这次,Cookie信息则存放在HTTP请求头(Request Header)了。

有了Cookie这样的技术实现,服务器在接收到来自客户端浏览器的请求之后,就能够通过分析存放于请求头的Cookie得到客户端特有的信息,从而动态生成与该客户端相对应的内容。

通常,我们可以从很多网站的登录界面中看到“请记住我”这样的选项,如果你勾选了它之后再登录,那么在下一次访问该网站的时候就不需要进行重复而繁琐的登录动作了,而这个功能就是通过Cookie实现的。

在程序中,会话跟踪是很重要的事情。理论上,一个用户的所有请求操作都应该属于同一个会话,而另一个用户的所有请求操作则应该属于另一个会话,二者不能混淆。例如,用户A在超市购买的任何商品都应该放在A的购物车内,不论是用户A什么时间购买的,这都是属于同一个会话的,不能放入用户B或用户C的购物车内,这不属于同一个会话。

而Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。即用户A购买了一件商品放入购物车内,当再次购买商品时服务器已经无法判断该购买行为是属于用户A的会话还是用户B的会话了。要跟踪该会话,必须引入一种机制。

Cookie就是这样的一种机制。它可以弥补HTTP协议无状态的不足。在Session出现之前,基本上所有的网站都采用Cookie来跟踪会话。

如果你把Cookies看成为http协议的一个扩展的话,理解起来就容易的多了,其实本质上cookies就是http的一个扩展。有两个http头部是专门负责设置以及发送cookie的,它们分别是Set-Cookie以及Cookie。当服务器返回给客户端一个http响应信息时,其中如果包含Set-Cookie这个头部时,意思就是指示客户端建立一个cookie,并且在后续的http请求中自动发送这个cookie到服务器端,直到这个cookie过期。如果cookie的生存时间是整个会话期间的话,那么浏览器会将cookie保存在内存中,浏览器关闭时就会自动清除这个cookie。另外一种情况就是保存在客户端的硬盘中,浏览器关闭的话,该cookie也不会被清除,下次打开浏览器访问对应网站时,这个cookie就会自动再次发送到服务器端。一个cookie的设置以及发送过程分为以下四步:

客户端发送一个http请求到服务器端

服务器端发送一个http响应到客户端,其中包含Set-Cookie头部

客户端发送一个http请求到服务器端,其中包含Cookie头部

服务器端发送一个http响应到客户端

这个通讯过程也可以用以下下示意图来描述:

在客户端的第二次请求中包含的Cookie头部中,提供给了服务器端可以用来唯一标识客户端身份的信息。这时,服务器端也就可以判断客户端是否启用了cookies。但是,用户可能在和应用程序交互的过程中突然禁用cookies的使用。

除了cookies,客户端还可以将发送给服务器的数据包含在请求的url中,比如请求的参数或者请求的路径中。 我们来看一个常规的http get 请求例子:

GET /index.php?foo=bar HTTP/1.1 Host: example.org

另外一种客户端传递数据到服务器端的方式是将数据包含在http请求的内容区域内。 这种方式需要请求的类型是POST的,看下面一个例子:

POST /index.php HTTP/1.1 Host: example.org Content-Type: application/x-www-form-urlencoded Content-Length: 7

foo=bar

在一个请求中,可以同时包含这两种形式的数据:

POST /index.php?myget=foo HTTP/1.1 Host: example.orgContent-Type: application/x-www-form-urlencoded Content-Length: 11

mypost=bar

这两种传递数据的方式,比起用cookies来传递数据更稳定,因为cookie可能被禁用,但是以GET以及POST方式传递数据时,不存在这种情况。我们可以将PHPSESSID包含在http请求的url中,就像下面的例子一样:

GET /index.php?PHPSESSID=12345 HTTP/1.1 Host: example.org

cookie的有效期

Cookie的maxAge决定着Cookie的有效期,单位为秒(Second)。Cookie中通过getMaxAge()方法与setMaxAge(int maxAge)方法来读写maxAge属性。 如果maxAge属性为正数,则表示该Cookie会在maxAge秒之后自动失效。浏览器会将maxAge为正数的Cookie写到对应的Cookie文件中。无论客户关闭了浏览器还是电脑,只要还在maxAge秒之前,登录网站时该Cookie仍然有效。下面代码中的Cookie信息将永远有效。

 `Cookie cookie =` `new` `Cookie(``"username"``,``"helloweenvsfei"``);` `// 新建Cookie`

`cookie.setMaxAge(Integer.MAX_VALUE);` `// 设置生命周期为MAX_VALUE`

`response.addCookie(cookie);` `// 输出到客户端`

如果maxAge为负数,则表示该Cookie仅在本浏览器窗口以及本窗口打开的子窗口内有效,Cookie信息保存在浏览器内存中,关闭窗口后该Cookie即失效。Cookie默认的maxAge值为–1。

cookie的不可跨域名

Cookie具有不可跨域名性。 域名www.google.com颁发的Cookie不会被提交到域名www.baidu.com去。这是由Cookie的隐私安全机制决定的。隐私安全机制能够禁止网站非法获取其他网站的Cookie。

正常情况下,同一个一级域名下的两个二级域名如www.helloweenvsfei.comimages.helloweenvsfei.com也不能交互使用Cookie,因为二者的域名并不严格相同。如果想所有helloweenvsfei.com名下的二级域名都可以使用该Cookie,需要设置Cookie的domain参数,例如:

`Cookie cookie =` `new` `Cookie(``"time"``,``"20080808"``);` `// 新建Cookie`

`cookie.setDomain(``".helloweenvsfei.com"``);` `// 设置域名`

`cookie.setPath(``"/"``);` `// 设置路径`

`cookie.setMaxAge(Integer.MAX_VALUE);` `// 设置有效期`

`response.addCookie(cookie);` `// 输出到客户端`

注意:domain参数必须以点(".")开始。

Cookie的安全属性

HTTP协议不仅是无状态的,而且是不安全的。使用HTTP协议的数据不经过任何加密就直接在网络上传播,有被截获的可能。使用HTTP协议传输很机密的内容是一种隐患。如果不希望Cookie在HTTP等非安全协议中传输,可以设置Cookie的secure属性为true。浏览器只会在HTTPS和SSL等安全协议中传输此类Cookie。下面的代码设置secure属性为true:

`Cookie cookie =` `new` `Cookie(``"time"``,` `"20080808"``);` `// 新建Cookie`

`cookie.setSecure(``true``);` `// 设置安全属性`

`response.addCookie(cookie);` `// 输出到客户端`

提示:secure属性并不能对Cookie内容加密,因而不能保证绝对的安全性。如果需要高安全性,需要在程序中对Cookie内容加密、解密,以防泄密。

JavaScript操作Cookie

Cookie是保存在浏览器端的,因此浏览器具有操作Cookie的先决条件。浏览器可以使用脚本程序如JavaScript或者VBScript等操作Cookie。这里以JavaScript为例介绍常用的Cookie操作。例如下面的代码会输出本页面所有的Cookie。

`<script>document.write(document.cookie);</script>`

由于JavaScript能够任意地读写Cookie,有些好事者便想使用JavaScript程序去窥探用户在其他网站的Cookie。不过这是徒劳的,W3C组织早就意识到JavaScript对Cookie的读写所带来的安全隐患并加以防备了,W3C标准的浏览器会阻止JavaScript读写任何不属于自己网站的Cookie。换句话说,A网站的JavaScript程序读写B网站的Cookie不会有任何结果。

单纯的以实现保存用户状态目的的话,只使用cookie也是可行的。其实在Cookie设计之初就是直接保存用户信息,但是由于cookie 是存在用户端,最关键是用户可以是可见的,并可以随意的修改,很不安全。所以session机制诞生了

Session机制

Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

同一个客户端每次和服务端交互时,不需要每次都传回所有的Cookie值,而是只要传回一个会话标识(SessionId),这个ID是客户端第一次访问服务器的时候生成的,而且每个客户端是唯一的。这样每个客户端就有一个唯一的ID,客户端只要传回这个ID就行了,这个ID通常是NAME为JSESIONID的一个Cookie。

Session的生命周期

Session保存在服务器端。为了获得更高的存取速度,服务器一般把Session放在内存里。每个用户都会有一个独立的Session。如果Session内容过于复杂,当大量客户访问服务器时可能会导致内存溢出。因此,Session里的信息应该尽量精简。

Session在用户第一次访问服务器的时候自动创建。需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session。如果尚未生成Session,也可以使用request.getSession(true)强制生成Session。

Session生成后,只要用户继续访问,服务器就会更新Session的最后访问时间,并维护该Session。用户每访问服务器一次,无论是否读写Session,服务器都认为该用户的Session“活跃(active)”了一次。

Session的有效期

由于会有越来越多的用户访问服务器,因此Session也会越来越多。为防止内存溢出,服务器会把长时间内没有活跃的Session从内存删除。这个时间就是Session的超时时间。如果超过了超时时间没访问过服务器,Session就自动失效了。

Session的超时时间为maxInactiveInterval属性,可以通过对应的getMaxInactiveInterval()获取,通过setMaxInactiveInterval(longinterval)修改。

Session的超时时间也可以在web.xml中修改。另外,通过调用Session的invalidate()方法可以使Session失效。

URL地址重写

URL地址重写是对客户端不支持Cookie的解决方案。URL地址重写的原理是将该用户Session的id信息重写到URL地址中。服务器能够解析重写后的URL获取Session的id。这样即使客户端不支持Cookie,也可以使用Session来记录用户状态。

要使用URL重写,可以通过response.encodeURL(url)进行实现;API对encodeURL的结束为,当浏览器支持cookie时,url不做任何处理;当浏览器不支持cookie的时候,将会重写URL将sessionid拼接到访问地址后。

cookie和session的区别

1.使用方式
  • cookie机制:如果不在浏览器中设置过期事件,cookie被保存在内存中,生命周期随浏览器的关闭而结束,这种cookie简称为会话cookie。如果在浏览器中设置了cookie的过期事件,cookie会被保存在硬盘中,关闭浏览器后,cookie数据仍然存在,直到过期事件结束才消失。cookie是服务端发给客户端的特殊信息,cookie是以文本的方式保存在客户端,每次请求时都带上它
  • session机制:当服务器收到请求需要创建session对象时,首先会检查客户端请求中是否包含sessionid。如果有sessionid,服务器将根据该id返回对应session对象。如果客户端请求中没有sessionid,服务器会创建新的session对象,并把sessionid在本次响应中返回给客户端。通常使用cookie方式存储sessionid到客户端,在交互中浏览器按照规则将sessionid发送给服务器。如果用户禁用cookie,则要使用URL重写,可以通过response.encodeURL(url)进行实现;API对encodeURL的结束为,当浏览器支持cookie时,url不做任何处理;当浏览器不支持cookie的时候,将会重写URL将sessionid拼接到访问地址后。
2.保持状态

cookie保存在浏览器端,session保存在服务器端

3.存储的大小

单个cookie保存的数据不能超过4kb
session大小没有限制,取决于服务器。

4.存储内容

cookie只能保存字符串类型,以文本的方式。
session通过类似与Hashtable的数据结构来保存,能支持任何类型的对象(session中可含有多个对象)

5.安全性

session的安全性大于cookie。原因如下:

​ ① sessionid存储在cookie中,若要攻破session首先要攻破cookie;
② sessionid是要有人登录,或者启动session_start才会有,所以攻破cookie也不一定能得到sessionid;
③ 第二次启动session_start后,前一次的sessionid就是失效了,session过期后,sessionid也随之失效。
④ sessionid是加密的。

综上所述,攻击者必须在短时间内攻破加密的sessionid,这很难。

token安全令牌

基于服务器验证方式暴露的一些问题

  • Seesion:每次认证用户发起请求时,服务器需要去创建一个记录来存储信息。当越来越多的用户发请求时,内存的开销也会不断增加。
  • 可扩展性:在服务端的内存中使用Seesion存储登录信息,伴随而来的是可扩展性问题。若服务器有多个,session无法在这些服务器中共享。
  • CORS(跨域资源共享):当我们需要让数据跨多台移动设备上使用时,跨域资源的共享会是一个让人头疼的问题。在使用Ajax抓取另一个域的资源,就可以会出现禁止请求的情况。
  • CSRF(跨站请求伪造):用户在访问银行网站时,他们很容易受到跨站请求伪造的攻击,并且能够被利用其访问其他的网站。因为 session id可以被伪造,没有采取加密的方法!!!,一旦攻击者通过session id伪造攻击,就会给服务器带来压力甚至击垮服务器。而token是通过加密算法(如:HMAC-SHA256算法)来实现session对象验证的,这样使得攻击者无法伪造token来达到攻击或者其他对服务器不利的行为。

基于Token的身份验证的过程如下:

使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:

  1. 客户端使用用户名跟密码请求登录;
  2. 服务端收到请求,去验证用户名与密码;
  3. 验证成功后,根据传过来的唯一标识userId(也可以是mac地址等唯一标识),服务端会通过一些算法,如常用的HMAC-SHA256算法,然后加一个密钥,生成一个token,然后通过BASE64编码一下之后将这个token发送给客户端;
  4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里;(通过js代码写入Local Storage,通过js获取,并不会像cookie一样自动携带)
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token;
  6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据。(验证的时候需要解密,解密就能知道用户的唯一标识,就能找到数据)

Token的优势

  1. 无状态、可扩展:
    Token机制在服务端不需要存储session信息,因为Token 自身包含了所有登录用户的信息,只需要在客户端的cookie或本地介质存储状态信息

    基于这种无状态和不存储Session信息,负载负载均衡器能够将用户信息从一个服务传到其他服务器上。

  2. 安全性
     请求中发送token而不再是发送cookie能够防止CSRF(跨站请求伪造)。即使在客户端使用cookie存储token,cookie也仅仅是一个存储机制而不是用于认证。不将信息存储在Session中,让我们少了对session操作。

    token是有时效的,一段时间之后用户需要重新验证。我们也不一定需要等到token自动失效,token有撤回的操作,通过token revocataion可以使一个特定的token或是一组有相同认证的token无效。

  3. 更适用于移动应用

    当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,Cookie是不被支持的(你需要通过Cookie容器进行处理)
    这时采用Token认证机制就会简单得多。

  4. 支持跨域访问
     我们提前先来谈论一下CORS(跨域资源共享),对应用程序和服务进行扩展的时候,需要介入各种各种的设备和应用程序。

posted @ 2021-04-02 19:41  Hhhighway  阅读(243)  评论(0编辑  收藏  举报