点击上方蓝色“程序猿DD”,选择“设为星标”

回复“资源”获取独家整理的学习资料!

来源 | 公众号「程序新世界」

越来越多的开发者开始学习并在实际项目中运用JWT(Json Web Token)技术来保护应用安全,很多公司的应用程序也开始使用JWT来管理用户会话信息,可谓风光无限。

任何技术框架都有自身的局限性,不可能一劳永逸,JWT也不例外。本文将从JWT的概念、基本原理和适用范围来剖析JWT并不是银弹,需要谨慎处理。

众所周知,如果账户信息(用户名和密码)泄露,存储在服务器上的隐私数据将受到毁灭性的打击,如果是管理员的账户信息泄露,系统还有被攻击的危险。那么,JWT的信息发生泄露,会带来什么样的影响?该如何防范?

1、什么是Token

Token(令牌)通常是指Security Token(安全令牌),可分为Hardware Token(硬件令牌),Authentication Token(授权令牌),USB Token(USB令牌),Cryptographic Token(加密令牌),Virtual Token(虚拟令牌)和 Key Fob(钥匙卡)。

Token的主要作用是验证身份的合法性,以允许计算机系统的用户可以操作系统资源。

生活中常见的令牌如:登录密码,指纹,声纹,门禁卡,银行电子卡等。

这里所讲的Token,主要目的是为计算机系统提供一个可以识别用户的任意数值,像“token123”的明文字符串,或像“41ea873f-3a4d-57c8-1e38-ef74f31015af”之类的加密字符。

2、什么是JSON Web Token

JSON Web Token(JWT)是一个基于RFC7519的开放数据标准,它定义了一种宽松且紧凑的数据组合方式,使用JSON对象在各应用之间传输加密信息。

该JSON对象可以通过数字签名进行鉴签和校验,一般可采用HMAC算法、RSA或者ECDSA的公钥/私钥对数据进行签名操作。

JWT通常有HEADER (头),PAYLOAD (有效载荷)和SIGNATURE (签名)三个部分组成,三者之间使用“.”链接,格式如下:

下面字符串是一个JWT的实际案例:

注意三者之间有一个点号(“.”)相连

为了更直观的了解JWT的创建过程和使用方式,通过一个简单的例子来演示这两个过程。

3、如何创建JWT?

JWT通常由“标头.有效载荷.签名”的格式组成。其中,标头用于存储有关如何计算JWT签名的信息,如对象类型,签名算法等。下面是JWT中Header部分的JSON对象实例:

其中,type表示该对象为JWT,alg表示创建JWT时使用HMAC-SHA256散列算法计算签名。有效载荷主要用于存储用户信息,如用户id,email,角色和权限信息等。下面是有效载荷的一个简单示例:

签名需要使用Base64URL编码技术对标头和有效载荷进行编码,并作为参数和秘钥一同传递给签名算法,生成最终的签名 (Signature)。以HMAC-SHA256算法为例,下面是生成签名的一个伪代码:

至此,已经了解了JWT的基本原理,接下来将使用Java来演示生成JWT的完整过程。

4、基于 Java 实现的 JWT

4-1、依赖

以Maven工程为例,需要在pom.xml文件中添加如下的配置信息:

如果是非Maven工程,可以到Maven中央仓库搜索jjwt,选择相应的版本(0.9.0)下载到本地,并将jar包添加到工程的类路径(classpath)中。

4-2、生成JWT

在工程中新建JJWTUitls.java工具类,使用jjwt提供的方法实现JWT的生成,实现细节如下:

此方法中JJWT已经处理好JWT标头(Header)的信息,我们只需要提供签名所使用的算法(如SignatureAlgorithm.HS256),有效载荷,主题(包含了用户信息),过期时间(exp-time)和秘钥即可,最后使用jjwt的builder()方法组装JWT。下面是生成秘钥方法key()的源代码:

4-3、解析JWT

使用JJWT解析JWT信息相对简单,首先获取秘钥,然后通过Jwts.parse()方法设置秘钥并JWT进行解析,实现细节如下:

4-4、测试JJWT

最后,在工程中新建一个JavaJWT.java 类,并在main方法中检验JJWTUtils工具类中生成和解析JWT两个方法是否有效。实现细节如下:

如上图所示,“jwt”将作为JWT标头(Header) “type” 的值,有效载荷(payload)中的主题信息如下:

且JWT签名的有效时间为60,000毫秒。执行main方法,输出信息如下所示:

从测试结果可以看出,成功的使用JJWT创建并解析了JWT。接下来,我们将了解到在实际的应用中,JWT对用户信息进行验证的基本流程。

5、 JWT 工作流程

在身份验证中,当用户成功登录系统时,授权服务器将会把JWT返回给客户端,用户需要将此凭证信息存储在本地(cookie或浏览器缓存)。

当用户发起新的请求时,需要在请求头中附带此凭证信息,当服务器接收到用户请求时,会先检查请求头中有无凭证,是否过期,是否有效。

如果凭证有效,将放行请求;若凭证非法或者过期,服务器将回跳到认证中心,重新对用户身份进行验证,直至用户身份验证成功。以访问API资源为例,下图显示了获取并使用JWT的基本流程:

在上述的案例中,我们使用HS256算法对JWT进行签名,在这个过程中,只有身份验证服务器和应用服务器知道秘钥是什么。

如果身份验证服务器和应用服务器完全独立,则应用服务器的JWT校验工作也可以交由认证服务器完成。

当客户端对应用服务器发起调用时,应用服务器会使用秘钥对签名进行校验,如果签名有效且未过期,则允许客户端的请求,反之则拒绝请求。

6、使用 JWT 的利弊

优势与劣势是相对而言的,这里主要以传统的Session模式作为参考,总结使用JWT可以获得优势以及带来的弊端。

6-1、 使用 JWT 的优势

使用JWT保护应用安全,至少可以获得以下优势:

更少的数据库连接:因其基于算法来实现身份认证,在使用JWT时查询数据的次数更少(更少的数据连接不等于不连接数据库),可以获得更快的系统响应时间。

构建更简单:如果应用程序本身是无状态的,那么选择JWT可以加快系统构建过程。

跨服务调用:可以构建一个认证中心来处理用户身份认证和发放签名的工作,其他应用服务在后续的用户请求中不需要(理论上)在询问认证中心,可使用自有的公钥对用户签名进行验证。

无状态:不需要向传统的Web应用那样将用户状态保存于Session中。

6-2、使用 JWT 的弊端

JWT不是万能的,使用JWT时可能会面临以下麻烦:

严重依赖于秘钥:JWT的生成与解析过程都需要依赖于秘钥(Secret),且都以硬编码的方式存在于系统中(也有放在外部配置文件中的)。如果秘钥不小心泄露,系统的安全性将受到威胁。

服务端无法管理客户端的信息:如果用户身份发生异常(信息泄露,或者被攻击),服务端很难向操作Session那样主动将异常用户进行隔离。

服务端无法主动推送消息:服务端由于是无状态的,将无法使用像Session那样的方式推送消息到客户端,例如过期时间将至,服务端无法主动为用户续约,需要客户端向服务端发起续约请求。

冗余的数据开销:一个JWT签名的大小要远比一个Session ID长很多,如果对有效载荷(payload)中的数据不做有效控制,其长度会成几何倍数增长,且在每一次请求时都需要负担额外的网络开销。

JWT相比于Session,OIDC(OpenId Connect)等技术还比较新,支持的库还比较少。而且JWT也并非比传统Session更安全,它们都没有解决CSRF和XSS的问题。因此,在决定使用JWT前,需要仔细考虑其利弊。

7、JWT 并非银弹

考虑这样一个问题:如果客户端的JWT令牌泄露或者被盗取,会发生什么严重的后果?有什么补救措施?

如果单纯依靠JWT解决用户认证的所有问题,那么系统的安全性将是脆弱的。

由于JWT令牌存储于客户端中,一旦客户端存储的令牌发生泄露事件或者被攻击,攻击者就可以轻而易举的伪造用户身份去修改/删除系统资源。

虽然JWT自带过期时间,但在过期之前,攻击者可以肆无忌惮的操作系统数据。通过算法来校验用户身份合法性是JWT的优势,也是最大的弊端——太过于依赖算法。

反观传统的用户认证措施,通常会包含多种组合,如手机验证码,人脸识别,语音识别,指纹锁等。

用户名和密码只做用户身份识别使用,当用户名和密码泄露后,在遇到敏感操作时(如新增,修改,删除,下载,上传),都会采用其他方式对用户的合法性进行验证(发送验证码,邮箱验证码,指纹信息等)以确保数据安全。

与传统的身份验证方式相比,JWT过多的依赖于算法,缺乏灵活性,而且服务端往往是被动执行用户身份验证操作,无法及时对异常用户进行隔离。

那是否有补救措施呢?答案是肯定的。接下来,将介绍在发生令牌泄露事件后,如何保证系统的安全。

8、JWT 爬坑指南

不管是基于Sessions还是基于JWT,一旦密令被盗取,都是一件棘手的事情。下面介绍JWT发生令牌泄露是该采取什么样的措施(包含但不局限于此)。

为了防止用户JWT令牌泄露而威胁系统安全,可以在以下方面完善系统功能:

清除已泄露的令牌:最直接也容易实现。将JWT令牌在服务端也存储一份,若发现有异常的令牌存在,则从服务端将此异常令牌清除。当用户发起请求时,强制用户重新进行身份验证,直至验证成功。服务端令牌的存储,可以借助Redis等缓存服务器进行管理,也可使用Ehcache将令牌信息存储在内存中。

敏感操作保护:在涉及到诸如新增,修改,删除,上传,下载等敏感性操作时,定期(30分钟,15分钟甚至更短)检查用户身份,如手机验证码,扫描二维码等手段,确认操作者是用户本人。如果身份验证不通过,则终止请求,并要求重新验证用户身份信息。

地域检查:通常用户会在一个相对固定的地理范围内访问应用程序,可以将地理位置信息作为辅助来甄别。如果发现用户A由经常所在的地区1变到了相对较远的地区2,或者频繁在多个地区间切换,不管用户有没有可能在短时间内在多个地域活动(一般不可能),都应当终止当前请求,强制用户重新进行验证身份,颁发新的JWT令牌,并提醒(或要求)用户重置密码。

监控请求频率:如果JWT密令被盗取,攻击者或通过某些工具伪造用户身份,高频次的对系统发送请求,以套取用户数据。针对这种情况,可以监控用户在单位时间内的请求次数,当单位时间内的请求次数超出预定阈值值,则判定该用户密令是有问题的。例如1秒内连续超过5次请求,则视为用户身份非法,服务端终止请求并强制将该用户的JWT密令清除,然后回跳到认证中心对用户身份进行验证。

客户端环境检查:对于一些移动端应用来说,可以将用户信息与设备(手机,平板)的机器码进行绑定,并存储于服务端中,当客户端发起请求时,可以先校验客户端的机器码与服务端的是否匹配,如果不匹配,则视为非法请求,并终止用户的后续请求。

总结

JWT的出现,为解决Web应用安全性问题提供了一种新思路。但JWT并不是银弹,仍然需要做很多复杂的工作才能提升系统的安全性。

当然,世上没有完美的解决方案,系统的安全性需要开发者积极主动地去提升,其过程是漫长且复杂的。

本文通过OpenWrite的Markdown转换工具发布

关注我,回复“加群”加入各种主题讨论群

  • 阿里内部禁用Executors创建线程池,为什么?

  • Token ,Cookie、Session傻傻分不清楚?

  • 使用 LocalDateTime 而不是 Date

  • 深入解读阿里云Redis开发规范:不要只会set&get

  • 在服务器上排除问题的头 5 分钟

朕已阅 

JWT 入坑爬坑指南相关推荐

  1. 从《编程之美》买票找零问题说起,娓娓道来卡特兰数——兼爬坑指南

    转自:从<编程之美>买票找零问题说起,娓娓道来卡特兰数--兼爬坑指南 引子: 大约两个月前,我在练习一些招聘的笔试题中,有一道和卡特兰数相关.那时还没来得及开始仔细看<编程之美> ...

  2. 蓝牙BLE(BlueTooth BLE)入门及爬坑指南

    前言 最近比较忙,两三周没有更新简书了,公司正好在做蓝牙BLE的项目,本来觉得挺简单的东西从网上找了个框架,就咔咔地开始搞,搞完以后才发现里面还有不少坑呢,故而写一篇蓝牙BLE入门及爬坑指南,旨在帮助 ...

  3. php jwt token 解析,JSON Web Token(JWT)入坑详解

    JSON Web Token(JWT)入坑详解 龙行    PHP    2019-6-17    1651    0评论 /** JWT生成类 **/ class Jwt { private $al ...

  4. paddlepaddle 人脸识别爬坑指南

    综述 爬坑一天,整出来一套还行的方案,特此分享爬坑心得~ 因为整体代码结构和上篇手写数字的文章里代码结构比较相似,所以这里只贴出部分代码 网络结构 目前采用的两套模型是普通cnn以及vgg,效果不错, ...

  5. 微信公众号JS-SDK多图上传爬坑指南

    一.wx.chooseImage爬坑 出现的问题: 安卓将chooseImage 方法返回的 localId 放在img标签的src属性下能够显示图片 IOS将chooseImage 方法返回的 lo ...

  6. iOS-通俗易懂的微信支付接入和爬坑指南,十分钟轻松搞完

     现在基本所有的App都会接入支付宝支付以及微信支付,也有很多第三方提供给你 SDK帮你接入,但是这种涉及到支付的东西还是自己服务器搞来的好一些,其实搞懂了 逻辑非常的简单,下面直接给大家说说下基本流 ...

  7. Nuxt(安装部署)爬坑指南

    Nuxt.js使用详细说明 这篇文章主要向大家介绍Nuxt爬坑,主要内容包括基础应用.实用技巧.原理机制等方面,希望对大家有所帮助. https://www.shangmayuan.com/a/dcd ...

  8. Insightface项目爬坑指南+使用本地数据集训练流程(MXNET版)

    其实半年多前就已经把insightface训练等一系列环节弄熟了,不得不说IBUG组的这个模型确实是开源界的翘楚,但是还是存在一些问题在某些程度上和商汤云从等大厂存在一点差距,这不妨碍大部分人日常人脸 ...

  9. Tinker + Bugly + Jenkins 爬坑之路

    前阵子 Android 端的线上崩溃比较多,热修复被提上日程.实现方案是 Tinker,Jenkins 打包,最后补丁包上传到 Bugly 进行分发.主要在 Jenkins 打包这一块爬了不少坑,现记 ...

最新文章

  1. 给GPT-2加上“人类偏好”补丁,它说的话就越来越有人情味了丨代码已开源
  2. 由浅入深之Jq选择器(2)
  3. LeetCode之Find All Numbers Disappeared in an Array
  4. searchsploit漏洞查找工具使用指南(exploit-db.com 离线工具)
  5. DPM 检测源码分析
  6. 智能优化算法:适应度相关优化算法 - 附代码
  7. 新版犀牛书该不该入手?
  8. PropertyUtils.copyProperties 属性值复制失败
  9. 浏览器中使用Github
  10. 构建股票交易平台专业术语
  11. 鼠标右键转圈圈_了解原理并解决鼠标右键转圈圈
  12. java工程师面试题大全100%公司笔试题你都能碰到几个
  13. C#查找Excel重复值(多列)
  14. 每日一练:第十一天——侦探推理
  15. 智能语义搜索引擎:一站式检索服务、打通数据壁垒、充分挖掘数据价值 | 百万人学AI评选
  16. SRGAN超分辨率网络
  17. VOD (Video On Demand),视频点播技术
  18. 图片随鼠标滑轮滚动变大变小
  19. 矩阵分析与应用(7)
  20. 业界最全的Redis可视化工具横向评测

热门文章

  1. linux sort 排序命令简介
  2. python flask gunicorn nginx 部署
  3. npm install 因网络链接慢 卡住解决方法
  4. python3 str is not callable 问题解决
  5. Android开发工具——ADB(Android Debug Bridge) 二HOST端
  6. Linux 下查看文件的命令介绍
  7. libvirt 启动 qemu 的过程
  8. Win2K下关联进程/端口之代码初步分析
  9. Linux初学者接住了---Linux常用命令
  10. mysql 表空间收缩_【135期】谈谈MySQL中的重做日志,回滚日志,以及二进制日志的区别及各自作用...