会话跟踪技术:Cookie 和Session

2,054 阅读12分钟

会话跟踪是web程序中常用的技术,用来跟踪用户的整个会话。
目前普遍存在四种会话跟踪技术:

  • URL重写,
  • 隐藏表单域,
  • Cookie,
  • Session。 这里主要说下cookie和session。
    Cookie 通过客户端记录用户信息,Session通过服务端记录用户信息 !
    简单来说就是cookie是存储在客户端的(浏览器),而session是存储在服务端的。

简单点理解 会话追踪的原理就是由于HTTP是无状态的,当有登录状态,需要区分用户的时候,服务端不知道对方是谁,所以就给客户端的用户们每人发一个会话标识,这样服务端就可以根据这个不同的id知道谁是谁了

一、 Session的发展史:

  1. 在很久以前,web网页基本上只是浏览,随着web交互的兴起,有了登录加购物车等,这样服务端就需要知道这个人是谁,谁加了什么。
  2. 因为HTTP是无状态的,所以想出来的办法就是给大家每个人发一个会话标识(session id)。( 简单点说就是一个字符串,每个人收到的不一样,每次发起请求时,浏览器把这个字符串告诉服务端,服务端就知道谁是谁了。)
  3. 但是缺点是如果上千万的人都来访问,服务器就要保存上千万的session id ,对服务端来说压力太大,限制了服务器的扩展能力。而且如果是集群,会有在A机器上登录,那么B机器上没有这个人的session id 的问题。

    • 当然可以使用会话粘滞解决这个问题,就是让用户请求一直粘连在机器A上,但是这样如果机器A挂了就完蛋了。
    • 也可以使用session复制,但是这个方法太笨重了。
    • 还可以把session id 集中存储到一个地方,但是会有单点失败的可能,也就是说负责session登录的那个机器如果挂了, 所以人都要重新登录一遍。
    • 比较推荐的是把session 保存在 redis 里。方便存储和查询

session的原理:

Session是由应用服务器维持的一个服务器端的存储空间,用户在连接服务器时,会由服务器生成一个唯一的SessionID,用该SessionID 为标识符来存取服务器端的Session存储空间。而SessionID这一数据则是保存到客户端,用Cookie保存的,用户提交页面时,会将这一 SessionID提交到服务器端,来存取Session数据。这一过程,是不用开发人员干预的。所以一旦客户端禁用Cookie,那么Session也会失效。

再详细些:

  • 当一个Session开始时,Servlet容器会创建一个HttpSession对象,那么在HttpSession对象中,可以存放用户状态的信息

  • Servlet容器为HttpSession对象分配一个唯一标识符即Sessionid,Servlet容器把Sessionid作为一种Cookie保存在客户端的 浏览器

  • 用户每次发出Http请求时,Servlet容器会从HttpServletRequest对象中取出Sessionid,然后根据这个Sessionid找到相应的HttpSession对象,从而获取用户的状态信息

session结束生命周期的两种办法:

  1. 一个是Session.invalidate()方法,不过这个方法在实际的开发中,并不推荐,可能在强制注销用户的时候会使用;
  2. 一个是当前用户和服务器的交互时间超过默认时间后,Session会失效

用户浏览这个Web应用的不同网页时,始终处于一个Session中。

其实当浏览器关闭的时候,浏览器并没有向服务器发送关闭session的请求, 那么session为什么访问不到了呢?因为浏览器关闭后,cookie不存在了,当我们重新打开浏览器窗口时,之前的cookie不在了,服务端也找不到对应的sessionid,所以会【再发一个新的】,而原先的会等到默认时间到了就销毁了。

二、Cookie:

定义:

Cookie是由客户端保存的小型文本文件(最大支持4096字节),其内容为一系列的键值对。 是由W3C组织提出的,目前已经成为标准,所有主流浏览器都支持Cookie。 cookie的作用是与服务器进行交互,作为http规范的一部分而存在的。

注意: 如果浏览器不支持cookie或者禁用了,cookie功能就失效了。比如 ios 安卓等 不支持cookie因为他们用的是原生的系统,而不是浏览器

注意事项(重点):

  • 一般而言, 对于跨站请求,浏览器是不会发送凭证信息的,但是如果将XMLHttpRequest 的 withCredentials =true ,才会带上该ajax请求所在域的cookie,从而使cookie可以随着请求发送。并且服务端应该返回Access-Control-Allow-Credentials:true 响应头,否则浏览器将不会把响应的结果传递给发出请求的脚本程序,以保证信息安全。给一个带有withCredentials的请求发送响应的时候,服务器端必须指定允许请求的域名,不能使用'*'.否则会失败。
    • axios和jQuery在同域ajax请求时会带上cookie, 跨域请求不会, 跨域请求需要设置 withCredentials 和服务端响应头
    • 服务端如果设置了httpOnly: true,那么带有该属性的cookie 客户端将无法读取(可以预防xss攻击)。
      image.png image.png

使用场景:

cookie和session组合在一起可以作为用户认证机制之一: Session-Cookie机制

工作原理:

服务器通过Set-Cookie响应头字段来指示浏览器保存Cookie, 浏览器通过Cookie请求头字段来告诉服务器之前的状态。 Cookie中包含若干个键值对,每个键值对可以设置过期时间。 Cookie需要由HTTP服务器设置,保存在浏览器中,在用户访问其他页面时,会在HTTP请求中附带上该服务器之前设置的cookie。

sequenceDiagram
浏览器->>服务器: 发起请求
服务器->>服务器: 收到HTTP请求,计算应返给浏览器的HTTP响应。在响应头加入Set-Cookie字段,它的值是要设置的Cookie。
服务器-->>浏览器: 收到响应
浏览器-)浏览器: 浏览器在响应头中发现Set-Cookie字段,会将该字段的值保存在内存或者硬盘中。
浏览器-->>服务器: 第二次请求,会将服务器设置的Cookie附加在HTTP请求的头字段Cookie中。

cookie的属性:

  除了name与value之外,Cookie还具有其他几个常用的属性。每个属性对应一个getter方法与一个setter方法。

  • String name: 该Cookie的名称。Cookie一旦创建,名称便不可更改
  • Object value: 该Cookie的值。如果值为Unicode字符,需要为字符编码。如果值为二进制数据,则需要使用BASE64编码
  • int maxAge: 该Cookie失效的时间,单位秒。如果为正数,则该Cookie在maxAge秒之后失效。如果为负数,该Cookie为临时Cookie,关闭浏览器即失效,浏览器也不会以任何形式保存该Cookie。如果为0,表示删除该Cookie。默认为–1
  • boolean secure: 该Cookie是否仅被使用安全协议传输。安全协议。安全协议有HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false
  • String path: 该Cookie的使用路径。如果设置为“/sessionWeb/”,则只有contextPath为“/sessionWeb”的程序可以访问该Cookie。如果设置为“/”,则本域名下contextPath都可以访问该Cookie。注意最后一个字符必须为“/”
  • String domain: 可以访问该Cookie的域名。如果设置为“.google.com”,则所有以“google.com”结尾的域名都可以访问该Cookie。注意第一个字符必须为“.”
  • String comment: 该Cookie的用处说明。浏览器显示Cookie信息的时候显示该说明
  • int version:该Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范

服务端设置cookie

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

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

cookie.setPath("/");                              // 设置路径
cookie.setSecure(true);                           // 设置安全属性
cookie.setMaxAge(Integer.MAX_VALUE);               // 设置有效期

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

而从客户端读取Cookie时,包括maxAge在内的其他属性都是不可读的,也不会被提交。浏览器提交Cookie时只会提交name与value属性。maxAge属性只被浏览器用来判断Cookie是否过期。

1. cookie的 domain (域名):

cookie 是有域的,根据cookie的规范(隐私安全机制),浏览器只会操作当前域名的cookie,也就是说google不能操作baidu的cookie。
需要注意的是,虽然网站images.google.com与网站www.google.com同属于Google,但是域名不一样,二者同样不能互相操作彼此的Cookie。如果需要所有一级域名下的二级域名都使用同一个cookie,需要设置cookie的domain属性。

因为Cookie存在不能跨域问题,所以如果需要跨域认证的话需要使用Token认证方式

2. cookie 的路径 path(允许访问Cookie的路径):

路径与域一起构成cookie的作用范围。 设置为“/”时允许所有路径使用Cookie。path属性需要使用符号“/”结尾。页面只能获取它属于的Path的Cookie。例如/session/test/a.jsp不能获取到路径为/session/abc/的Cookie。

3. cookie的值value 编码 :

  • 中文与英文字符不同,中文属于Unicode字符,在内存中占4个字符,Cookie中使用Unicode字符时需要对Unicode字符进行编码,否则会乱码。
    • 一般使用UTF-8编码即可。不推荐使用GBK等中文编码,因为浏览器不一定支持,而且JavaScript也不支持GBK编码。
  • 英文属于ASCII字符,内存中只占2个字节。
  • 还可以使用二进制数据。例如在Cookie中使用数字证书,提供安全度。使用二进制数据时也需要进行编码。

4. cookie 的有效期 maxAge(Cookie的有效期):

HTTP1.0 中使用的是expires,是个GMT。HTTP1.1 中 被max-age替代了(秒数)

cookie的maxAge决定着Cookie的有效期,单位为秒(Second)。Cookie中通过getMaxAge()方法与setMaxAge(int maxAge)方法来读写maxAge属性。

  • 【正数】: 则表示该Cookie会在maxAge秒之后自动失效。浏览器会将maxAge为正数的Cookie持久化,即写到对应的Cookie文件中。无论客户关闭了浏览器还是电脑,只要还在maxAge秒之前,登录网站时该Cookie仍然有效。
  • 【负数】: 则表示该Cookie仅在本浏览器窗口以及本窗口打开的子窗口内有效,关闭窗口后该Cookie即失效。maxAge为负数的Cookie,为临时性Cookie,不会被持久化, 不会被写到Cookie文件中。Cookie信息保存在浏览器内存中,因此关闭浏览器该Cookie就消失了。Cookie默认的maxAge值为–1。
  • 【0】: 则表示删除该Cookie。Cookie机制没有提供删除Cookie的方法,因此通过设置该Cookie即时失效实现删除Cookie的效果。失效的Cookie会被浏览器从Cookie文件或者内存中删除

会话cookie :

若不设置时间,则表示这个cookie的生命期为浏览器会话期间,关闭浏览器窗口,cookie就会消失。 会话cookie一般不存储在硬盘而是保存在内存里,

5. cookie 的安全属性 secure:

secure 属性设置为true, 会限制浏览器只会在HTTPS和SSL等安全协议中传输此类Cookie(HTTP是非安全协议,不建议传输很机密的内容)。 但他并不能对Cookie内容加密,因而不能保证绝对的安全性。如果需要高安全性,需要在程序中对Cookie内容加密、解密,以防泄密。

注意:修改、删除Cookie时,新建的Cookie除value、maxAge之外的所有属性,例如name、path、domain等,都要与原Cookie完全一样。否则,浏览器将视为两个不同的Cookie不予覆盖,导致修改、删除失败。

domian、 path、expires、secure 都是服务端给浏览器的指示, 指定何时应该发送cookie。这些参数不会作为发送到服务器cookie信息的一部分,只有name=value会被发送

三、cookie和session的对比

cookiesession
数据存在客户端数据存在服务器
保存的是字符串保存的是对象
不安全,有csrf较安全
数据不能超过4k没有限制
可以设置生命周期,或永久保存在本地的文件浏览器关闭就消失
-存在服务器,服务器有压力
可以设置路径不区分路径

四,其他两种会话跟踪技术

1 隐藏表单域

<input type="hidden" id="xxx" value="xxx">

  • (参数存放)参数是存放在请求实体里的,因此没有长度限制,但是不支持 GET 请求方法,因为 GET 没有请求实体
  • (Cookie禁用)当Cookie被禁用时依旧能够工作
  • (持久性)不存在持久性,一旦浏览器关闭就结束

2 URL 重写

可以在 URL 后面附加参数,和服务器的请求一起发送,这些参数为键/值对

  • (参数存放)参数是存放在 url 里的,有1024长度限制
  • (Cookie禁用)当Cookie被禁用时依旧能够工作
  • (持久性)不存在持久性,一旦浏览器关闭就结束

五 总结:

session和cookie是常用的会话跟踪技术,session和cookie结合就可以成为session-cookie认证机制用来认证用户信息。用户的认证方式常用的有2种:Session-Cookie认证机制 和 Token认证机制(jwt是他具体的实现)。

cookie 的作用是与服务器进行交互,作为http规范的一部分而存在的,需要服务端set-cookie响应头传输给客户端,然后在客户端存储数据,是一种具体的存储方式。cookie不能跨域,容易被盗取,有csrf(跨站请求伪造)攻击。session 是服务端存储数据的,session只是一种服务端的概念,有很多实现方式。

Cookie会根据从服务端发送的响应报文中的一个set-cookie 的首部字段信息,通知客户端保存cookie。当下次客户端发送请求的时候, 会自动加上cookie发送给服务端。 浏览器通过Cookie请求头字段来告诉服务器之前的状态。

参考