Web身份验证详解:Cookie、Session、Base64与Token的应用与区别

在这里插入图片描述

🌟个人主页:时间会证明一切.

会话技术

会话:一次会话中包含多次请求和响应。

  • 一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止
  • 功能:在一次会话的范围内的多次请求间,共享数据
  • 方式:
    • 客户端会话技术:Cookie
    • 服务器端会话技术:Session

Cookie

Cookie:客户端会话技术,将数据保存到客户端,以后每次请求都携带 Cookie 数据进行访问,基于HTTP协议实现

当用户第一次访问并登陆一个网站的时候,Cookie的设置以及发送会经历以下4个阶段:

  1. 客户端发送一个请求到服务器
  2. 服务器返回一个 httpResponse 响应到客户端,其中包含 Set-Cookie 的响应头
  3. 客户端收到服务器返回的 Set-Cookie 响应头里的数据,将其保存 Cookie,之后向服务器发送请求时,httpRequest 请求中会包含一个 Cookie 的请求头
  4. 服务器可以通过检查该 Cookie 获取信息,返回响应数据

img

服务器向客户端发送 Cookie

Cookie 基本使用

  1. 创建 Cookie 对象,设置数据

    Cookie cookie = new Cookie("key","value");
    
  2. 发送 Cookie 到客户端 使用 response 对象

    response.addCookie(cookie)
    

Set-Cookie是通过HTTP响应头部的Set-Cookie字段来设置的。当服务器要向客户端设置一个新的Cookie时,会在HTTP响应中包含这个Set-Cookie字段。

例如,下面是一个包含Set-Cookie头部的HTTP响应示例:

HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: key=value

在这个示例中,服务器通过Set-Cookie头部将一个名为key的Cookie发送给客户端。该Cookie的值为value

当客户端收到这个Set-Cookie头部时,会解析其中的信息,并存储这个Cookie。在后续的请求中,客户端会将这个Cookie自动包含在请求头部的Cookie字段中发送给服务器。服务器接收到请求后,可以根据这个Cookie的值进行相应的处理。

客户端携带 Cookie 向服务器发送请求

在HTTP请求中,Cookie是通过包含在请求头部的"Cookie"字段中发送的。具体来说,Cookie会以键值对的形式表示,多个键值对之间使用分号(;)进行分隔。例如:

GET /example HTTP/1.1
Host: example.com
Cookie: key1=value1; key2=value2; key3=value3

在这个示例中,请求头部的"Cookie"字段携带了三个Cookie,即key1=value1、key2=value2和key3=value3。

服务器收到请求后,可以解析请求头部中的"Cookie"字段,以获取客户端发送的Cookie数据,并根据需要进行处理或响应

Cookie 使用细节

  • Cookie存活时间

    • 默认情况下,Cookie 存储在浏览器内存中,当浏览器关闭,内存释放,则 Cookie 被销毁
    • setMaxAge(int seconds):设置 Cookie 存活时间
      • 正数:将 Cookie 写入浏览器所在电脑的硬盘,持久化存储。到时间自动删除
      • 负数:默认值,Cookie 在当前浏览器内存中,当浏览器关闭,则 Cookie 被销毁
      • 零: 删除对应 Cookie
  • Cookie 存储中文

    • Cookie不能直接存储中文 在tomcat 8 之前 cookie中不能直接存储中文数据
    • 在tomcat 8 之后,cookie支持中文数据。特殊字符还是不支持,建议使用URL编码存储,URL解码解析
    • 如需要存储,则需要进行转码:URL编码

使用 Cookie 时存在的问题

  • 不安全,不要存储敏感数据,比如用户密码,账户余额,因为存储在客户端,容易被客户端篡改
  • 能存储的数据量不能超过 4KB
  • 有数量限制,一个浏览器针对一个网站最多存 20 个 Cookie,浏览器一般只允许存放 300 个 Cookie;
  • 移动端对 Cookie 的支持不是很好,而 Session 需要基于 Cookie 实现,所以移动端常用的是 token;
  • Cookie 为不可跨域的:每个 Cookie 都会绑定单一的域名,无法在别的域名下获取使用;

跨域问题

跨域的由来不得不提到 XSS 攻击。

全名:Cross-site scripting(跨站脚本攻击)。这是一种安全漏洞,攻击者可以利用这种漏洞在网站上注入恶意的客户端代码。若受害者运行这些恶意代码,攻击者就可以突破网站的访问限制并冒充受害者。简单地说,就是我可以在你的网站偷偷上运行我的代码,那有多危险。

为了应对这种情况,便有了浏览器的同源策略。

同源策源

这个策略是由浏览器去实现的,其目的在于限制请求方如何与另一个源的资源进行交互。

“源”你就理解为地址,但它的完整格式由协议、域名、端口组成,如:

https://store.company.com:8000

另一个客户端请求上面的地址,如果协议、域名、端口其中有一个不同,这两个就算两个源,客户端的行为要受到限制。

下表给出了与 URL http://store.company.com/dir/page.html 的源进行对比的示例:

URL 结果 原因
http://store.company.com/dir2/other.html 同源 只有路径不同
http://store.company.com/dir/inner/another.html 同源 只有路径不同
https://store.company.com/secure.html 失败 协议不同
http://store.company.com:81/dir/etc.html 失败 端口不同 ( http:// 默认端口是 80)
http://news.company.com/dir/other.html 失败 主机不同

不同源的请求,就被认为是跨域,是不被允许的。

Cookie跨域问题

Cookie是不可以跨域名的,隐私安全机制禁止网站非法获取其他网站的Cookie。
正常情况下,同一个以及域名下的两个二级域名也不能交互Cookie,比如test1.jianshu.com与test2.jianshu.com,因为二者简书的域名不完全相同,如果想要jianshu.com名下的二级域名都可以使用该Cookie,需要设置Cookie的domain参数为jianshu.com,这样使用test1.jianshu.com和test2.jianshu.com就能访问同一个域名了。

设置的过程,服务器设置cookie的时候,需要指定cookie的domain,当domain与当前host的匹配不上的时候,responseHeader里的set-cookie不会设置成功。这也就是cookie不支持跨域问题。

Session

服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器端的对象中

  • session 是另一种记录服务器和客户端会话状态的机制

  • session 是基于 cookie 实现的

  • session 存储在服务器端,可以理解为一个状态列表,他拥有一个唯一识别符号JSESSIONID,通常存放于 cookie 中

  • 在一次会话的多次请求间获取的session是同一个

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MXOSt1SF-1688566791979)(Cookie、Session 和 Token.assets/image-20230703141620004.png)]

Session 使用流程

  1. 首先,客户端会发送一个http请求到服务器端。
  2. 服务端接收请求后,创建对应的 session ,而每一个session是有一个唯一标识id的,tomcat自动将该session的id当作一个Cookie并发送一个http响应到客户端,这个响应头,其中就包含 Set-Cookie 头部。该头部包含了key = JSESSIONID,值=session唯一标识。比如:set-cookie: JSESSIONID=10(每个session的唯一标识)
  3. 浏览器接收到服务端返回的 JSESSIONID=10后,将此信息存入 Cookie 中,同时 Cookie 记录此 JSESSIONID 属于哪个域名。
  4. 当用户第二次发起请求时,请求会自动判断此域名下是否存在 Cookie 信息,如果存在浏览器会自动在请求头中添加 Cookie 发送到服务端
  5. 服务端接收请求,会从 Cookie 中获取 JSESSIONID,再根据 JSESSIONID查找对应的 Session 信息,如果没有找到说明用户没有登录或者登录失效,如果找到 Session 证明用户已经登录可执行后面操作。

Session 使用细节

Session 钝化、活化

  • 服务器重启后,Session 中的数据是否还在?
    • 钝化:在服务器正常关闭后,Tomcat 会自动将 Session 数据写入硬盘的文件中
    • 活化:再次启动服务器后,从文件中加载数据到 Session 中

Session销毁:

  • 默认情况下,无操作,30分钟自动销毁

    <session-config>
    	<session-timeout>30</session-timeout>
    </session-config>
    
  • 调用 Session 对象的invalidate()方法,Session 自动销毁

Cookie 和 Session 区别

  • Cookie 和 Session都是来完成一次会话内多次请求间数据共享的
  • 区别:
    • 存储位置:Cookie是将数据存储在客户端,Session将数据存储在服务端
    • 安全性:Cookie不安全,Session安全
    • 数据大小:Cookie最大4KB,Session无大小限制
    • 存储时间:Cookie可以长期存储,Session默认30分钟
    • 服务器性能:Cookie不占服务器资源,Session占用服务器资源

Base64算法

Base64是什么?

Base64 是一种二进制到文本的编码方式。如果要更具体一点的话,可以认为它是一种byte数组编码为字符串的方法,而且编码出的字符串只包含 ASCII 基础字符。

例如字符串ShuSheng007对应的 Base64 为U2h1U2hlbmcwMDc=。其中那个=比较特殊,是填充符,一会再说。

值得注意的是 Base64 不是加密算法,其仅仅是一种编码方式,算法也是公开的,所以不能依赖它进行加密。

为什么叫Base64?

因为它是基于(Base)64个字符的一种编码方式。使用其编码后的文本只包含64个ASCII码字符(偶尔加一个填充字符=),如下所示:

Base64使用到的64个 字符:

  • A-Z 26个
  • a-z 26个
  • 0-9 10个
  • + 1个
  • / 1个

下图是Base64码表,可以看到从0到63的每个数字都对应一个上面的一个字符。

img

Base64解决什么问题?

为什么各系统以及传输协议中二进制不兼容

导致各系统和传输协议中二进制不兼容的原因可能有以下几点:

  1. 数据表示方式:不同系统或协议可能使用不同的数据表示方式,例如大端字节序和小端字节序的区别。如果在数据交换过程中没有正确处理字节序,就会导致数据解析错误。

  2. 数据类型和长度:不同系统或协议可能对数据类型和长度的定义存在差异。例如,一个系统使用32位整数表示某个字段,而另一个系统使用64位整数表示相同的字段。在数据交换时,如果没有对数据类型和长度进行适当的转换和匹配,就会导致数据解析错误或数据截断。

  3. 数据编码方式:不同系统或协议可能使用不同的数据编码方式,如ASCII、UTF-8、UTF-16等。如果在数据交换时没有正确指定和处理编码方式,就会导致数据解析错误或乱码。

  4. 数据格式和协议规范:不同系统或协议可能使用不同的数据格式和协议规范。例如,一个系统使用JSON格式进行数据交换,而另一个系统使用XML格式。如果在数据交换时没有按照正确的格式和规范进行解析和处理,就会导致数据解析错误或通信失败。

  5. 加密和压缩算法:不同系统或协议可能使用不同的加密和压缩算法。如果在数据交换时没有正确处理加密和压缩算法,就无法正确解析和还原数据。

为了解决这些二进制不兼容性问题,通常需要进行数据格式转换、字节序转换、数据类型转换、编码转换等操作,以确保数据在不同系统和协议之间正确解析和传输。

Base64 就是为了解决各系统以及传输协议中二进制不兼容的问题而生的

为啥 Base64 大家就兼容了呢?因为 Base64 满足了各方的需求,各方说了,我们只保证支持 ASIIC 中那些基础字符,其他的我们不能保证,于是 Base64 就去从那些基础字符里挑了64个,所以大家都高兴了。

Base64编码是一种将二进制数据转换为可打印字符的编码方式。它通过将原始二进制数据转换为由64个字符组成的可打印字符集,从而解决了各系统和传输协议中二进制不兼容的问题。以下是Base64可以解决二进制不兼容性的原因:

  1. 可打印字符集:Base64编码使用64个可打印字符(A-Z,a-z,0-9和"+“,”/")表示二进制数据,这些字符在大多数系统和协议中都是兼容的。通过将二进制数据转换为可打印字符集,可以确保数据能够在不同系统和协议之间正确解析和传输。

  2. 字符集一致性:Base64编码使用的字符集在大多数系统中是标准的,无论是ASCII字符集还是Unicode字符集。这种一致性确保了数据在不同系统和协议中的兼容性。

  3. 无格式限制:Base64编码只关注数据的二进制表示,而不关注数据的具体格式。这意味着可以对任意类型的二进制数据进行Base64编码,无论是图像、音频、文本还是其他类型的数据。因此,通过Base64编码,可以将任何类型的二进制数据转换为字符串形式,以便在各种系统和协议之间传输

需要注意的是,Base64编码会导致数据稍微增加约33%的大小,因为每3个字节的二进制数据会编码成4个字符。因此,在使用Base64编码传输数据时,需要考虑到数据大小的增加。另外,Base64编码只是解决二进制数据在传输和解析过程中的兼容性问题,而不会解决二进制数据在语义和语法上的兼容性。对于更复杂的数据兼容性问题,可能需要进行更多的数据转换和处理操作。

使用场景

  • 证书
  • 电子邮件的附件,因为附件往往有不可见字符
  • xml 中如果像嵌入另外一个 xml 文件,直接嵌入,往往 xml 标签就乱套了, 不容易解析,因此,需要把 xml 编译成字节数组的字符串,编译成可见字符。
  • 网页中的一些小图片,可以直接以 Base64 编码的方式嵌入,不用再链接请求消耗网络资源。
  • 较老的纯文本协议 SMTP ,这些文本偶尔传输一个文件时,需要用 Base64

Base64算法

  1. Base64算法是一种将二进制数据转换为可打印字符的编码算法。下面是Base64编码的基本步骤:

    我们将使用二进制数据 “Hello World!” 进行编码。

    1. 将 “Hello World!” 转换为对应的ASCII码:
      • ASCII码:72 101 108 108 111 32 87 111 114 108 100 33
    2. 将ASCII码转换为二进制:
      • 01001000 01100101 01101100 01101100 01101111 00100000 01010111 01101111 01110010 01101100 01100100 00100001
    3. 将二进制数据按照每3个字节分组:
      • 01001000 01100101 01101100 01101100 01101111 00100000 01010111 01101111 01110010 01101100 01100100 00100001
    4. 将每个字节转换为8位二进制数,并拼接在一起:
      • 010010000110010101101100 011011000110111100100000 010101110110111101110010 011011000110010000100001
    5. 将24位的二进制数划分为4个6位的小组:
      • 010010 000110 010101 101100 011011 000110 111100 100000 010101 110110 111101 110010 011011 000110 010000 100001
    6. 将每个6位的二进制数转换为十进制数,对应于Base64字符集中的索引:
      • 18 6 21 44 27 6 60 32 21 54 61 50 27 6 16 33
    7. 使用Base64字符集中对应索引的字符替代每个6位二进制数:
      • S G V k b G 8 g V u Z + y G B Q
    8. 得到最终的Base64编码字符串:
      • “SGVsbG8gV29ybGQh”

    所以,将二进制数据 “Hello World!” 使用Base64编码后得到的Base64编码字符串是 “SGVsbG8gV29ybGQh”。

    解码时,可以按照相反的步骤进行操作:

    1. 将Base64编码字符串按照每4个字符进行分组。

    2. 将每个Base64字符转换为对应的6位二进制数。

    3. 将这4个6位的二进制数拼接在一起,得到一个24位的二进制数。

    4. 将这个24位的二进制数划分为3个8位的字节。

    5. 将每个8位二进制数转换为十进制数,得到原始的二进制数据。

    6. 如果Base64编码字符串中存在填充字符’=',则去除填充字符。

    需要注意的是,Base64编码是一种用于数据传输和存储的编码方式,并不是加密算法。它可以将二进制数据转换为可打印字符,但不能提供数据的保密性。

下图是维基百科上面的一个例子

假如我们的原文为Man,那么下图演示了如何按照上面的步骤将其编码为Base64字符串

img

可以发现Man对应的Base64为TWFu.现在大家应该明白为什么只有64个字符了吧?因为算法将将8bit分割成6bit了,而6bit的取值范围为0~63

Base64字符串末尾的=是什么

有时我们会在Base64字符末尾会看到=,有时1个,有时2个,这是为啥?

通过上面的我们知道了Base64编码过程是3个字符一组的进行,如果原文长度不是3的倍数怎么办呢? 例如我们的原文为Ma,它不够3个,那么只能在编码后的字符串中补=了。缺一个字符补一个,缺两个补两个即可,所以有时候你会看见base64字符串结尾有1个或者2个=

img

Base64 DataURI格式

有时你会发现web页面传给你的base64字符串前面有类似下面的东东。

data:image/jpeg;base64,    /9j/4AA...

这是DataURI,大部分浏览器支持直接打开这类二进制数据,但是我们要格外注意,如果你只是想要真实的Base64内容就需要取,后边的内容

Token

JSON Web Token(缩写 JWT)是目前最流行的跨域认证解决方案,本文介绍它的原理和用法。

img

一、跨域认证的问题

互联网服务离不开用户认证。一般流程是下面这样。

  1. 用户向服务器发送用户名和密码。
  2. 服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。
  3. 服务器向用户返回一个 session_id,写入用户的 Cookie。
  4. 用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
  5. 服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。

存在的问题

  • 扩展性(scaling)不好。单机当然没有问题,如果是服务器集群,或者是跨域的服务导向架构,就要求 session 数据共享,每台服务器都能够读取 session。

  • 举例来说,A 网站和 B 网站是同一家公司的关联服务。现在要求,用户只要在其中一个网站登录,再访问另一个网站就会自动登录,请问怎么实现?

解决方案

  1. 一种解决方案是 session 数据持久化,写入数据库或别的持久层。各种服务收到请求后,都向持久层请求数据。这种方案的优点是架构清晰,缺点是工程量比较大。另外,持久层万一挂了,就会单点失败。

  2. 另一种方案是服务器索性不保存 session 数据了,所有数据都保存在客户端,每次请求都发回服务器。JWT 就是这种方案的一个代表。

二、JWT 的原理

JWT 的原理是,服务器认证以后,生成一个 JSON 对象,发回给用户,就像下面这样。

{
   
   
  "姓名": "张三",
  "角色": "管理员",
  "到期时间": "2023年7月1日0点0分"
}

以后,用户与服务端通信的时候,都要发回这个 JSON 对象。服务器完全只靠这个对象认定用户身份。为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名(详见后文)。

服务器就不保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展。

三、JWT 的数据结构

实际的 JWT 大概就像下面这样。

img

它是一个很长的字符串,中间用点(.)分隔成三个部分。注意,JWT 内部是没有换行的,这里只是为了便于展示,将它写成了几行。

JWT 的三个部分依次如下。

  • Header(头部)
  • Payload(负载)
  • Signature(签名)

写成一行,就是下面的样子。

Header.Payload.Signature

img

下面依次介绍这三个部分。

3.1 Header

Header 部分是一个 JSON 对象,描述 JWT 的元数据,通常是下面的样子。

{
   
   
  "alg": "HS256",
  
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值