jwt重放攻击_4个点搞懂JWT、JWS、JWE

1.JWT是何物,有哪些常用的场景

JWT(json web token)是设计一种简洁,安全,无状态的token的实现规范rfc7519,通常用于网络请求方和网络接收方之间的网络请求认证。

b30f98dc82c52d459ba9cc9048bf7244.png

jwt的常用场景

1.1: restful api接口的无状态认证, 在传统的web应用中,我们通常采用session认证。

session认证流程:

  • 客户端将用户名/密码通过某种加密的方式发送给服务器

  • 服务器接收到客户端请求之后进行验证,验证通过后使用Set-Cookie将用户的唯一sessionid放入到cookie当中,并将生成的sessionid和用户的关联信息存入到内存。

  • 客户端第二次访问后服务器从当前cookie中取出sessionid并从内存中拿到相同的sessionid. 如果不存在,或者没有携带sessionid则说明该用户登陆过期,或者未登陆。

session认证的一些缺点:

  • 由于使用session进行认证的方式必须存储sessionid,当用户量过大时对服务器内存消耗影响巨大. 如果你没有设置session的过期时间(关闭浏览器并不会导致cookie消失)那么对你的服务器来说消耗是致命的。

  • 如果你没有将session存在一个所有服务器都可以获取得到的地方如redis, 那么意味着在本台服务器上面存储的sessionid其他服务器无法获取。用户进行请求时必须请求到这台服务器上面。可扩展性较差。

  • 跨平台性较差,传统的session认证方式在移动端很难行得通。你必须开发二套不同的逻辑对web和移动端进行认证。

jwt认证流程:

  • 客户端将用户名/密码通过某种加密的方式发送给服务器。

  • 服务器接收到客户端请求后进行验证,验证通过服务器生成token返回给客户端。客户端将token存储在本地。

  • 客户端每次请求将token携带在http header头中, 服务器端将token取出进行解密。

jwt认证的优点:

  • 服务器端无需保存token,以加解密的方式代替存储,节省了内存空间。

  • 无状态的token不依赖于服务器保存会话信息,更利于水平扩展。

  • 相比于传统的session认证方式,jwt对移动端的支持更友好。

可以看出jwt认证解决了传统的session认证的一些不足之处。

1.2: 一次性认证:

如需要对某一个应用进行授权使用,此时就可以将jwt进行携带访问。

2.jwt的组成和生成方式

2.1jwt主要由三个部分组成,分别是头部(header),载荷(payload),签名(signature)组成。

header:

  • 头部是用来声明此jwt的类型和加密算法,它们通常由alg和typ这二个字段组成。

  • alg字段通常用于表示加密采用的算法。

  • typ字段通常用于表示类型。

 {"typ":"JWT", "alg":"HS256"} //示范的jwt header头

payload:

  • 载荷就是我们存放公共参数/私有参数的地方.通俗点说该字段就是存放系统中用户的信息和jwt本身的一些信息,rfc文档本身替我们提供了一组字段的声明 (Claims)

  • iss: 该字段表示jwt的签发者。可以用你的应用唯一标识或者高权限的userid填充此字段。

  • sub: 该jwt面向的用户。

  • aud: jwt的接收方。

  • exp: jwt的过期时间,通常来说是一个时间戳。

  • iat: jwt的签发时间,常来说是一个时间戳。

  • jti:此jwt的唯一标识。通常用于解决请求中的重放攻击。该字段在大多数地方没有被提及或使用。因为使用此字段就意味着必须要在服务器维护一张jti表, 当客户端携带jwt访问的时候需要在jti表中查找这个唯一标识是否被使用过。使用这种方式防止重放攻击似乎让jwt有点怪怪的感觉, 毕竟jwt所宣称的优点就是无状态访问。-.-

//一个正儿八经的payload示范
{
    "iss": "appid_xxxxxx"
    "sub": "012345122",
    "exp": "1572246721840",
    "iat": "1592246721840"
}

signature签名流程:

1.首先将header和payload进行base64编码,然后使用"."将header和payload拼接起来。类似于像下面这样:

String base64data = Base64.encode(header)+"."+Base64.encode(payload)

2.在将payload和header进行base64之后进行签名,得到签名后的数据。签名所使用的算法来自于header头中的alg字段。签名过程类似于像下面这样:

    final JWSSigner signer = new ECDSASigner(this.privateKey);

             this.signature = signer.sign(base64data);
            //第一步, 实例化一个签名对象
            //第二步,对base64data 进行签名

3.签名之后将签名的值和base64之后的header和payload用"."号连接起来。此时一个完整的jwt就出来啦。

jwt的最终结构: header.payload.signature

3.使用jwe来使你的jwt更加安全

签名到底在干什么:

在上面我们所谈到的jwt仅仅是签名后的jwt。在这里我们需要明白一个概念,那就是签名并不能保证数据的安全,也就是说如果有人获取到了你的jwt那么他可以通过转码得到你jwt当中所有的信息。那么读者可能会有点想骂人了,你特么上面说了那么多连一个数据安全都不能保证那么我看那么多有啥作用- -. 别急,我们先来了解一下签名的概念。其实对于签名更专业点的来说就是进行了一次哈希散列,对于散列我们首先要保证一下四点概念.

  • 相同的输入将始终产生相同的输出。

  • 多个不同的输入不应产生相同的输出。

  • 从输出到输入应该是不可能的。

  • 给定输入的任何修改都将导致哈希值发生巨大变化。

从上面4点大家看明白了吗?哈希与身份验证结合使用,可以产生强有力的证据来证明给定的消息尚未被修改。也就是说这个jwt从我这里签发以后无法改变,从而保证了数据来源的可靠性。

当客户端携带jwt进行请求时服务器在执行一遍签名步骤。如果签名的值一样就表示这个jwt是可靠的。此时我们在客户端和服务器之间就建立一种可信任的token机制。

应该怎样保证数据安全:

对于如何保证jwt本身的数据安全很多文章或文档都可以提及,我们可以把上面所生成的jwt成为jws(JSON Web Signed). 他本身的数据并没有进行加密。

此时如果我们想保证数据的安全就需要使用jwe(JSON Web Encryption)对jwt进行加密。jwe加密的秘文如下所示

// jwe相对于jws来说多了二个组成部分。
eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.
     OKOawDo13gRp2ojaHV7LFpZcgV7T6DVZKTyKOMTYUmKoTCVJRgckCL9kiMT03JGe
     ipsEdY3mx_etLbbWSrFr05kLzcSr4qKAq7YN7e9jwQRb23nfa6c9d-StnImGyFDb
     Sv04uVuxIp5Zms1gNxKKK2Da14B8S4rzVRltdYwam_lDp5XnZAYpQdb76FdIKLaV
     mqgfwX7XWRxv2322i-vDxRfqNzo_tETKzpVLzfiwQyeyPGLBIO56YJ7eObdv0je8
     1860ppamavo35UgoRdbYaBcoh9QcfylQr66oc6vFWXRcZ_ZT2LawVCWTIy3brGPi
     6UklfCpIMfIjf7iGdXKHzg.
     48V1_ALb6US04U3b.
     5eym8TW_c8SuK0ltJ3rpYIzOeDQz7TALvtu6UG9oMo4vpzs9tX_EFShS8iB7j6ji
     SdiwkIr3ajwQzaBtQD_A.
     XFBoMYUZodetZdvTiFvSkQ

jwe的5个组成部分:

  • JWE header: 描述用于创建jwe加密密钥和jwe密文的加密操作,类似于jws中的header。参数不一一描述,详情请见jwe header参数

  • JWE Encrypted Key:用来加密文本内容所采用的算法。

  • JWE initialization vector: 加密明文时使用的初始化向量值,有些加密方式需要额外的或者随机的数据。这个参数是可选的。

  • JWE Ciphertext:明文加密后产生的密文值。

  • JWE Authentication Tag:数字认证标签。

  //一个完整的jwe json结构
  {
      "protected":"jwe受保护的header头",
      "unprotected":"JWE Shared Unprotected Header数据",
      "header":"",
      "encrypted_key":"密钥加密后数据    ",
      "aad":"额外的认证数据",
      "iv":"同上的 JWE initialization vector",
      "ciphertext":"同上的JWE Ciphertext",
      "tag":"同上的JWE Authentication Tag"
     }

jwe创建流程:

  • 根据头部 alg 的声明,将header头进行编码

  • 随机生成密钥

  • 加密密钥

  • 生成iv如果不需要,此步骤可以省略.

  • 加密原始报文

  • 生成认证算法得到Authentication Tag.

  • 如果明文有声明zip压缩,那么压缩明文

Base64.encode(header)+"."+Base64.encode(encrypted_key)+","+Base64.encode(iv)+"."+Base64.encode(ciphertext)+"."Base64.encode(tag)

4. jwt的缺点以及常见的理解误区

缺点:

  • 无法主动的过期token. 常见的场景为后台踢出用户或封禁用户,此时若是token还在生效
    时间范围内,那么意味着该用户在被踢出系统后还可以在这个时间范围内进行访问。又或者用户修改了密码,此时原token依然可以进行加解密也就代表着用户仍然可以继续访问。更为致命的是大多数客户端会将token存放在Local Storage或者vuex中,这意味着除非用户点击退出登陆。否则就算关闭软件在重新打开也会造成原密码可以登陆的假象。

  • jwt对比于传统的session认证方案并不会提高运行效率,因为本质上jwt做的是一个以时间换空间的动作。频繁的加解密会带来不小的性能开销。

常见的理解误区:

  • 对jwt进行存储,这个是最常见的理解误区。事实上很多人都觉得将jwt进行存储可以完美的解决主动过期的问题, 然而这是一种赔了夫人又损兵的做法。既无法节省空间也无法节省时间。如果你的应用必须要主动过期的功能,那么我推荐你使用传统的session,事实上传统的session也有不少成熟的解决方案。如spring-session等。

  • jwt被盗用会导致数据泄漏不安全, 事实上使用jwe加密的jwt是不存在数据不安全的问题的。第二,jwt的数据一般都是非敏感数据,由于签名机制的存在所以你盗用了jwt做不了任何事情。

  • 不存储如何实现退出功能。直接在客户端清除token就行了。因为服务器不存储所以只需要在客户端清除token就可以做到用户退出。

  • 将token的时期设计的非常长。这是一个会造成很多隐性问题的设计,比如上述的密码修改等问题。这个时候可以参见oauth2的做法,将token的过期时间设置为一小时,但是增加一个refreshToken。客户端在没有触发退出或者修改密码等操作时通过refreshToken来刷新token。

3ed33b60b54a33626436121add2ec5cb.png

7c80a036209c1d8697c375f31cd8857b.png 你在看吗?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/359489.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Verification Mind Games---how to think like a verifier像验证工程师一样思考

1. 有效的验证需要验证工程师使用不同于设计者的思维方式思考问题。具体来说,验证更加关心在严格遵循协议的基础上发现设计里面的bug,搜索corner cases,对设计的不一致要保持零容忍的态度。mindset:一套人们应该持有的确定的态度&…

discuz安装_手动搭建 Discuz! 论坛

一、搭建LAMP环境安装软件(Apache、MariaDB、PHP)yum install httpd php php-fpm php-mysql mariadb mariadb-server -y2.启动服务systemctl start httpdsystemctl start mariadbsystemctl start php-fpm3.安装后首次启动mariadb设置mysql_secure_installation4.登录 MariaDB&a…

关系数据库的几种设计范式介绍

关系数据库的几种设计范式介绍1、第一范式(1NF) 在任何一个关系数据库中,第一范式(1NF)是对关系模式的基本要求,不满足第一范式(1NF)的数据库就不是关系数据库。 所谓…

蓝桥杯 1223 第 2 场 小白入门赛

蓝桥小课堂-平方和 模拟 1 2 2 2 3 2 ⋯ n 2 n ⋅ ( n 1 ) ⋅ ( 2 n 1 ) 6 1^22^23^2\cdotsn^2\dfrac{n\;\cdot\;(n 1)\;\cdot\;(2n1)}{6} 122232⋯n26n⋅(n1)⋅(2n1)​。 write(n * (n 1) * (n * 2 1) / 6);房顶漏水啦 m a x ( 最大的行 − 最小的行 , 最大的列 −…

jar包是什么意思_面试难度五颗星:JVM有Full GC,为什么还会 OutOfMemoryError?

点击上方蓝色“后端面试那些事儿”,选择“设为星标”学最好的别人,做最好的我们来源:R 大zhihu.com/question/38511221问题:R大回复平时有逛知乎的习惯,一般对JVM相关话题比较感兴趣。偶然看到这个问题,结果…

mapreduce介绍_MapReduce:简单介绍

mapreduce介绍MapReduce是Google流行的一种并行编程技术。 它用于处理大量数据。 仅通过将工作并行分配给多台机器,就可以在合理的时间内完成这种处理。 每台机器都处理一小部分数据。 MapReduce是一种编程模型,使开发人员可以专注于编写处理数据的代码&…

系统执行sql很慢达梦工具执行很快的简单解决方式

现象描述:系统功能查询很慢,拷贝查询sql到达梦工具中执行速度很快 1.问题分析: 达梦SQL执行耗时异常问题排查_qq_39693441的博客-CSDN博客_sql耗时分析 2.解决方式1: 在程序sql中拼接随机数如: select /*动态随机数*…

PHP在程序处理过程中动态输出内容

在安装discuz或其他一些开源产品的时候&#xff0c;在安装数据库时页面上的安装信息都是动态输出出来的&#xff0c;主要通过php两个函数来实现的&#xff0c; flush();ob_flush(); 代码如下 <html xmlns"http://www.w3.org/1999/xhtml"><head> <meta…

roads 构筑极致用户体验_长安马自达「悦马星空」计划上线,为用户带来极致服务体验...

日前,第十八届广州车展顺利举行。期间各大汽车品牌齐聚亮相,这其中,也包括众人熟悉的长安马自达。据悉,在本次车展上,长安马自达除携品牌全系车型次世代MAZDA3 昂克赛拉、2020款MAZDA CX-5、MAZDA CX-30和MAZDA CX-8亮相外,还正式发布「悦马星空」用户共创计划。资料显示,「悦马…

从数百万个光纤(而不是数千个线程)中查询数据库

jOOQ是在Java中执行SQL的好方法&#xff0c; Quasar光纤带来了大大提高的并发性 我们很高兴在平行宇宙的 Fabio Tudone的jOOQ博客上宣布另一个非常有趣的来宾帖子。 Parallel Universe开发了一个开源堆栈&#xff0c;使开发人员可以轻松地在JVM上对极端的并发应用程序进行编码…

matlab向量的排序(自写函数)

function a_ed arraysort(a) %冒泡排序法 for i 1:length(a)-1%进行多少次比较for j1i:length(a)%每次求出最大的数&#xff0c;放在最后if(a(j)<a(i))tem a(i);a(i) a(j);a(j) tem;endenda_ed a; endclc; clear; a [2 4 4 6 14 0 2 8 4 1 9 4] b arraysort(a)转载于…

标准错误处理机制——error

在 Golang 中&#xff0c;错误处理机制一般是函数返回时使用的&#xff0c;是对外的接口&#xff0c;而异常处理机制 panic-recover 一般用在函数内部。 error 类型介绍 error 类型实际上是抽象了 Error() 方法的 error 接口&#xff0c;Golang 使用该接口进行标准的错误处理。…

ejb 2.0 3.0_EJB 3.1全局JNDI访问

ejb 2.0 3.0如本系列前面部分所述&#xff0c;EJB 3.0版规范的主要缺点是缺少可移植的全局JNDI名称。 这意味着没有可移植的方式将EJB引用链接到应用程序外部的Bean。 EJB v。3.1规范用自己的话填补了这一定义&#xff1a; “一个标准化的全局JNDI名称空间和一系列相关的名称空…

Oracle11.2.0.4 RAC安装文档

1 环境配置 参考官方文档《Grid Infrastructure Installation Guide for Linux》 1.1 软件环境 操作系统&#xff1a; [roothowe1 ~]# cat /etc/redhat-release Red Hat Enterprise Linux Server release 6.2 (Santiago) [roothowe1 ~]# uname -a Linux howe1 2.6.32-220.el6.i…

威海二职工业机器人专业_现在各大专开设的工业机器人专业前景如何?

我就是某专科学校工业机器人技术专业人的学生&#xff0c;专业是现在专业几个负责人15年向教育局申请申办的&#xff0c;16年正式招生&#xff0c;我也有幸作为第一届学生来到了该学校。先说教学吧&#xff0c;因为是第一届所以很多设备、设施都不完善&#xff0c;我觉得最重要…

协同遗漏的效果–使用简单的NIO客户端/服务器测量回送延迟

在这篇文章中&#xff0c;我演示了许多想法和技术&#xff1a; 如何编写一个简单的非阻塞NIO客户端/服务器 协调遗漏的影响 如何测量百分位数的延迟&#xff08;相对于简单平均&#xff09; 如何在计算机上计时延迟回送 我最近正在为客户端服务器应用程序开发低延迟基准测…

python 画蜘蛛_如何学习 R 绘图?

写在前面&#xff1a;为啥不用excel绘制这些图&#xff0c;用PoweBI&#xff0c;帆软BI等可视化软件来绘图&#xff0c;不是更方便吗&#xff1f;的确&#xff0c;这些工具都很方便&#xff0c;但同时&#xff0c;它们显得很呆&#xff0c;不够灵活&#xff0c;更为致命的是&am…

conflicting types for ‘方法名’ 的错误

将main()的实现写在drawShapes(),drawCircle(),drawRectangle()...之前. 结果编译的时候出现了 conflicting types for "方法名"的错误。故到网上查找答案&#xff0c;发现在这里需要严格按照函数出现的先后顺序才能成功编译&#xff0c;也就是main()要定义在最后&a…

Oracle用户system解锁

1.首先进入sql plus窗口&#xff08;参见上一篇文章&#xff09; 2.进入后&#xff1a;输入select username,account_status from dba_users where usernameSYSTEM; 3.查询system用户的状态和用户名&#xff0c;这里能查询出密码&#xff0c;但是查出来的密码是密文&#xff0c…

captcha库_将CAPTCHA添加到您的GWT应用程序

captcha库什么是验证码&#xff1f; 在一个充满恶意机器人的世界中&#xff0c;您应该怎么做才能保护您宝贵的Web应用程序&#xff1f; 您真正应该做的基本事情之一就是向其中添加CAPTCHA功能。 如果您不熟悉&#xff08;听起来有些奇怪&#xff09;&#xff0c;则CAPTCHA是确保…