cookie、session、token与JWT

http协议

超文本传输协议(HyperText Transfer Protocol,HTTP)一种用于分布式、协作式和超媒体信息系统的应用层协议,是基于 TCP/IP 协议的应用层协议。通常运行于TCP上,指定了客户端发送什么样的请求信息,得到来自服务端返回回来的相对应的响应。

我们知道HTTP是一种无状态的协议,无状态的意思就是说是没有记忆的,前后的HTTP请求是相互独立互不干扰的,也就是说客户端每向服务端发送请求时,后发送的请求无法得知前发送请求所包含的各种状态数据。如果还想要得到前发送请求响应的数据,需要重新发送该请求,即http的响应数据无法持久化。但是我们一般的需求是有需要保留之前请求的数据的,就如同最为常见的用户登录功能,当你用户登录后要进行其他业务的处理需要用到用户信息时,其就要重新在通过用户密码获取用户信息,这显然是不合理的,需要考虑将登录时的响应数据进行持久化。

cookie

cookie将信息以key-value的形式存储至客户端浏览器,当我们再次向服务端发起请求时,其请求会携带所有的cookie信息至服务端,以解决http无状态的问题。

Cookie使用限制:
  • 发向服务器的所有 cookie 的最大数量(空间)不能超过:4KB
  • 对于不同的浏览器能创建的cookie数量是有限的,原始规范中限定每个域名下不超过 20 个 cookie,之后在一次更新中增加了限制数量, 可参考下面表格。
浏览器版本 Cookie的数量限制 Cookie的总大小限制
IE6 20个/每个域名 4095个字节
IE7 50个/每个域名 4095个字节
IE9 50个/每个域名 4095个字节
Chrome 50个/每个域名 大于80000
FireFox 50个/每个域名 4097个字节
  • 客户端用户如果设置禁止 Cookie,则 Cookie 不能建立。
Cookie时效性:

cookie的存储时间是大部分是有限制临时的,其规定cookie信息保存在浏览器上一段指定的时间,等时间到期之后其cookie信息将自动被清楚。

Cookie的工作流程:
  1. 客户端向服务端发送一个http请求
  2. 服务端接收到请求后,服务器端接受客户端请求后,返回一个http响应给客户端,响应中包含着要存入cookie的信息,并通过set-cookie将信息存入浏览器中
  3. 当客户端再次向服务端发送http请求时,请求中就会带上cookie信息发送至服务端,服务端在对该信息进行验证,执行相应的逻辑处理,再返回响应。
    cookie、session、token与JWT_第1张图片
cookie 常用属性
属性 说明
name Cookie 的名称及相对应的值,必须是字符串类型,不区分大小写,一旦创建,名称便不可更改
value Cookie的值,如果值为Unicode字符,需要为字符编码。如果为二进制数据,则需要使用BASE64编码
domain 指定 cookie 使用的所属域名,默认是当前域名,例如设置为“.csdn.net”,则所有以“csdn.net”结尾的域名都可以访问该Cookie。
path 指定 cookie 在哪个路由下生效,默认是 ‘/’。如设置“www.csdn.net/blog”则只有 ./blog 下的路由可以访问到该 cookie
expires 过期时间(GMT时间格式),在设置的某个时间点后该 cookie 就会失效。以客户端的时间为准,cookie一般默认存储的,当关闭浏览器时及删除cookie
max-age cookie 失效的时间,单位秒。该参数优先级高于优先级高于 expires ,如果值为正数,则该 cookie 在 maxAge 秒后失效。如果为负数则关闭浏览器即失效删除 。如果为 0,表示删除该 cookie 。默认为 -1。
HttpOnly 设置该属性将使js脚本无法读写该 cookie 的信息,但还是能通过 Application 中手动修改 cookie,一定程度上可以防止 CSRF 攻击
secure 该 cookie 是否仅被使用安全协议传输。安全协议有 HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false。当 secure 值为 true 时,cookie 在 HTTP 中是无效的。
comment 该Cookie的用处说明,浏览器显示Cookie信息的时候显示该说明。
version Cookie使用的版本号。0表示遵循Netscape的Cookie规范,1表示遵循W3C的RFC 2109规范
cookie 在JavaScript中的设置

cookie在JS中设置、读取、删除的常用封装方法:

<script type="text/javascript">
document.cookie='name=value;domain=.domain.com;path=/;expires=time;HttpOnly;secure'
/**
 * 设置cookie
 */
function setCookie(key,value,days){
	var exp = new Date();
	exp.setTime(exp.getTime() + days*24*60*60*1000);
    document.cookie=key+"="+value+"; expires="+exp.toGMTString();
}
/**
 *  获取cookie
 */
function getCookie(key){
	var arr;
    var reg = new RegExp("(^| )" + key+ "=([^;]*)(;|$)");
    if (arr = document.cookie.match(reg)) return decodeURI(arr[2]);
    else return null;
}
/**
 * removeCookie 移除cookie
 */
function removeCookie(key){
    setCookie(key,"",-1); // 把cookie设置为过期
};
</script>

Session

我们知道cookie是将信息存储在本地浏览器,对于本地浏览器存储的信息我们很容易对其获取破译这样来说信息数据相对不那么安全。而session则是将信息存储在服务器,这样对于数据信息来说就变得更加的安全,不易被窃取。

Session 代表着服务器和客户端一次会话的过程。在整个会话过程中,不管页面的进行跳转,其存储的数据信息都不会丢失,知道会话关闭或者 Session 超时失效会话结束。

session机制

session属于一种服务器端的机制,服务器使用一种类似于散列表的结构保存信息。

浏览器第一次发送请求时,服务器会自动生成了Session,并且生成了唯一标识Session ID来标识这个Session并返回给浏览器。当我们从浏览器发送要存储数据至Session中的请求给服务器时,我们的请求里会携带存放有Session ID的Cookie一并发送到服务器上,服务器就会根据我们的sessionid在服务器端开辟一个内存空间来存放数据,同时把内存空间的地址通过cookie的形式返回给浏览器。当我们下一个请求需要调用数据时,服务器就会根据我们cookie存储的内存空间地址来到内存中,找到对应session拿出数据。

一般Session ID会有时间限制,超时后毁掉这个值,默认30分钟,当我们关闭浏览器的时候,服务器端的session也会被摧毁。

cookie、session、token与JWT_第2张图片

session时效性

通过上述我们知道session id存储在cookie中,而真正的数据是存储在服务器中,那么session的时效性是如何

  • 客户端(session id):过期时间和Cookie过期一致,如果没设置,默认跟随浏览器的关闭而失效。
  • 服务端(session data):没有设置session过期时间的话,默认是30分钟。过期后其session的数据结构就不可用。

cookie和session的区别

  1. 安全性: Session 比 Cookie 安全,Session 是存储在服务器端的,Cookie 存储在客户端的,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗。
  2. 存取值的类型不同:Cookie 只支持存字符串数据,Session 可以存任意数据类型。
  3. 有效期不同: Cookie可设置为长时间保持,Session 一般失效时间较短,客户端关闭(默认情况下)或者 Session 超时都会失效。
  4. 存储大小不同: 单个 Cookie 保存的数据不能超过 4K,Session 可存储数据远高于
    Cookie,但是当访问量过多,会占用过多的服务器资源。

在选用cookie或session时应当考虑本身的需求进行合理化选择。一般将重要信息存放到session中,其他需要保留的信息放在cookie中,大多数使用Session + Cookie来进行操作。

Token(令牌)

Token是服务器端生成的用于验证用户登录状态的加密数据,Token验证服务器端不需要存储用户会话所需的配置等数据,只需要后端将Token进行验证签名,然后再发给浏览器。每次用户请求时带上这一段token信息,服务端拿到此信息进行解密后就能判断此用户。

token解决的问题

我们知道HTTP协议是无状态的,无状态以为着需要验证每次请求来辨别客户端的身份。一般我们通过在服务端存储的登录信息来辨别请求,而基于服务端验证的方式存在一些问题:

  • 使用session进行验证时,当用户量越来越多,其占用服务器的内存资源将会不断的加大。

  • 可扩展性:在服务端的内存中使用Seesion存储登录信息,伴随而来的是可扩展性问题。

  • CORS(跨域资源共享):当我们需要让数据跨多台移动设备上使用时,会出现跨域问题。

  • CSRF(跨站请求伪造):cookie和session都会受到csrf的攻击,一个典型的例子:假如用户已经登陆了银行网页,但此时点进了一个钓鱼网站新开了一个tab页,而该网站直接向银行网页发起了一个转账请求,如果银行网页未对csrf攻击进行防护,那么该请求就会携带我们银行的cookie信息骗过银行的服务器验证并最终完成转账,形成 CSRF 攻击。

token的优势
  1. 无状态
    不将用户信息存在服务器或session中,只需携带token信息去服务端进行签名验证即可,适用于分布式微服务

  2. 安全性
    请求中发送token而不再是发送cookie能够防止CSRF(跨站请求伪造)。即使在客户端使用cookie存储token,cookie也仅仅是一个存储机制而不是用于认证。同时token是有时效的,一段时间之后用户需要重新验证。

  3. 可扩展性
    Tokens能够创建与其它程序共享权限的程序。使用tokens时,可以提供可选的权限给第三方应用程序。当用户想让另一个应用程序访问它们的数据,我们可以通过建立自己的API,得出特殊权限的tokens。例如我们可以通过其他社交账户来登录CSDN

  4. 多平台跨域
    CORS(跨域资源共享),对应用程序和服务进行扩展的时候,需要介入各种各种的设备和应用程序。只要用户有一个通过了验证的token,数据和资源就能够在任何域上被请求到。

Token认证机制
  1. 客户端使用用户名跟密码向服务端发起请求登录,服务端进行用户校验

  2. 若用户校验成功,服务端会签发一个由服务端持有秘钥通过加密算法对数据进行加密的token,并将该token信息传送给客户端

  3. 客户端收到 token 信息以后,会把它存储起来,比如放在 cookie(只用于存储) 里或者 localStorage 里

  4. 客户端在之后每次向服务端请求资源的时,都会携带服务端签发的 token,携带方式将 token 放到 HTTP 的 Header中或其它方式(请求头的 Authorization 字段中使用Bearer 模式添加 token )

  5. 服务端收到请求后,会去验证客户端请求携带着的 token,如果验证成功,就向客户端返回请求的数据,失败在返回错误信息。一般采用验证中间件进行校验

cookie、session、token与JWT_第3张图片

JWT

JSON Web Token(简称 JWT)是token的一种实现方式,并且基本是java web领域的事实标准,是目前最流行的跨域认证解决方案。
JWT 的原理是,服务器认证以后,生成一个 JSON 对象,为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名,发回给用户。

JWT的数据结构

JWT是一个很长的没有分行的字符串,中间以点(.)分隔成三个部分。
cookie、session、token与JWT_第4张图片
JWT 的三个部分由上到下依次为:

  • Header(头部)
    Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是这样子的:
    { "alg": "HS256", "typ": "JWT" }

alg属性表示签名的算法(algorithm),默认是 HMAC SHA256(写成 HS256);
typ属性表示这个令牌(token)的类型(type),JWT 令牌统一写为JWT。
最后,将上面的 JSON 对象使用 Base64URL 算法(Base64算法替换在 URL 里面有特殊含义的值)转成字符串。

  • Payload(负载)
    Payload 部分是一个 JSON 对象,用来存放实际需要传递的数据(如用户信息)。JWT 规定有7个官方字段,供选用,除了官方提供的还可自定义。并且用该对象使用Base64URL 算法转成字符串。
  • iss (issuer):签发人
  • exp (expiration time):过期时间
  • sub (subject):主题
  • aud (audience):受众
  • nbf (Not Before):生效时间
  • iat (Issued At):签发时间
  • jti (JWT ID):编号
  • Signature(签名)
    该部分是对前两部分的签名,防止数据篡改。

首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

JWT的实现

JWT的实现根据语言的不同有不同的实现方式,以下提供一些实现案例:

  • golang实现JWT用户验证:实战——golang实现JWT验证登录
Token 和 JWT 的区别

Token:服务端验证客户端发送过来的 Token 时,还需要查询数据库获取用户信息,然后验证 Token 是否有效。
JWT: 将 Token 和 Payload 加密后存储于客户端,服务端只需要使用密钥解密进行校验(校验也是 JWT 自己实现的)即可,不需要查询或者减少查询数据库,因为 JWT 自包含了用户信息和加密的数据。

本文为编程小白自学问题归纳,如有错误与不足敬请指正!

你可能感兴趣的:(Web基础知识,session,jwt,cookie,网络)