JWT的实现原理

一篇文章告诉你JWT的实现原理

发布于 3 个月前 作者 axetroy 3097 次浏览 来自 分享

在使用 JWT 的时候,有没有想过,为什么我们需要 JWT?以及它的工作原理是什么?

我们就来对比,传统的 session 和 JWT 的区别

我们以一个用户,获取用户资料的例子

传统的 session 流程

  1. 浏览器发起请求登陆
  2. 服务端验证身份,生成身份验证信息,存储在服务端,并且告诉浏览器写入 Cookie
  3. 浏览器发起请求获取用户资料,此时 Cookie 内容也跟随这发送到服务器
  4. 服务器发现 Cookie 中有身份信息,验明正身
  5. 服务器返回该用户的用户资料

JWT 流程

  1. 浏览器发起请求登陆
  2. 服务端验证身份,根据算法,将用户标识符打包生成 token, 并且返回给浏览器
  3. 浏览器发起请求获取用户资料,把刚刚拿到的 token 一起发送给服务器
  4. 服务器发现数据中有 token,验明正身
  5. 服务器返回该用户的用户资料

你发现了吗?好些并没有什么区别,除了 session 需要服务端存储一份,而 JWT 不需要

但实际上区别大了去了

  1. session 存储在服务端占用服务器资源,而 JWT 存储在客户端
  2. session 存储在 Cookie 中,存在伪造跨站请求伪造攻击的风险
  3. session 只存在一台服务器上,那么下次请求就必须请求这台服务器,不利于分布式应用
  4. 存储在客户端的 JWT 比存储在服务端的 session 更具有扩展性

对比完了 session 和 JWT 的区别,下面我们来看看那它的实现原理

JWT 工作原理

首先 JWT 长这个样

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpcCI6IjEyNy4wLjAuMSIsInV1aWQiOiJmZjEyMTJmNS1kOGQxLTQ0OTYtYmY0MS1kMmRkYTczZGUxOWEiLCJpYXQiOjE1Mjc1MjMwMTd9.1C01cpOf1N3M9YAYvQjfcLbDGHZ4iPVncCGIoG-lpO0jHOIA_ZHtSMDvK1nzArLpGK5syQSwExsZJz2FJsd2W2TUiHQYtzmQTU8OBXX6mfSZRlkts675W5_WhIiOEwz69GFSD0AKXZifCRgIpKLC0n273MRMr0wJnuBi9ScfJ7YjSiqCr7qyQ5iXeOdS3ObT3wdjjk-Wu9wbWM7R25TFb-7PEZY7r_e8jmczPCVcNbOYegedu73T4d30kRn2jKufTGntD5hR6T9AQsgAMwVR1edEFflWb772TmrHI7WZOAivsBCN9sr4YiyYMvE8lcz_mBsgsunugGiHA3DGxB2ORbjIC8NPm8FI25zGOh9JIM2r_jFFTIm9GiuKtC8Ck8N3-eWi9u1NgBxwLdgN5JyCORnIOlciQEsScg-3SdCTM5LH_j6CeqQNwJxT4-oENzqLSTDJbP-SOj9nnx8HnJ5wh3n64rAvtc89CeTk7PhWFjksHDifngN-cnaszl5lqoF1enz5i9FYYELSjM-G7jns2SyY1MQeLRjuEDriPZtFaGmTW-RLH3gJfQXtbdpEo0_nHBqXEohwoN_FLKo4BNrEwshpyA7vkBpCQC0QALKyC1_L1Q5qduR6dDcqRozAo2VqJXmAKN0rvhLuIEHZkicOZY0Ds4So4GCcleqvFcxm1HQ

眼睛看仔细一些,你会发现 JWT 里面有两个.

数据格式是这样的 header.payload.signature

我们逐个逐个部分去分析,这个部分到底是干嘛的,有什么用

Header

JWT 的 header 中承载了两部分信息

{
"alg": "RS256",
"typ": "JWT"
}
  • alg: 声明加密的算法
  • typ: 声明类型

对这个头部信息进行 base64,即可得到 header 部分

const headerBuff = Buffer.from(
JSON.stringify({
alg: "RS256",
typ: "JWT"
})
); const header = headerBuff.toString("base64"); console.log(header);
// eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9

Payload

payload 是主体部分,意为载体,承载着有效的 JWT 数据包,它包含三个部分

  • 标准声明
  • 公共声明
  • 私有声明

标准声明的字段

interface Stantar {
iss?: string; // JWT的签发者
sub?: string; // JWT所面向的用户
aud?: string; // 接收JWT的一方
exp?: number; // JWT的过期时间
nbf?: number; // 在xxx日期之间,该JWT都是可用的
iat?: number; // 该JWT签发的时间
jti?: number; //JWT的唯一身份标识
}

标准中建议使用这些字段,但不强制。

公共声明的字段

interface Public {
[key: string]: any;
}

公共声明字段可以添加任意信息,但是因为可以被解密出来,所以不要存放敏感信息。

私有声明的字段

interface Private {
[key: string]: any;
}

私有声明是 JWT 提供者添加的字段,一样可以被解密,所以也不能存放敏感信息。

上面的 JWT 的 payload 结构是这样的

{
"ip": "127.0.0.1",
"uuid": "ff1212f5-d8d1-4496-bf41-d2dda73de19a",
"iat": 1527523017
}

同样是通过 base64 加密生成第二部分的 payload

const payloadBuffer = Buffer.from(
JSON.stringify({
ip: "127.0.0.1",
uuid: "ff1212f5-d8d1-4496-bf41-d2dda73de19a",
iat: 1527523017
})
); const payload = payloadBuffer.toString("base64"); console.log(payload);
// eyJpcCI6IjEyNy4wLjAuMSIsInV1aWQiOiJmZjEyMTJmNS1kOGQxLTQ0OTYtYmY0MS1kMmRkYTczZGUxOWEiLCJpYXQiOjE1Mjc1MjMwMTd9

Signature

signature 是签证信息,该签证信息是通过headerpayload,加上secret,通过算法加密生成。

公式 signature = 加密算法(header + "." + payload, 密钥);

上面的 header 中,我们已经定义了加密算法使用 RS256,也已经实现了生成headerpayload,下面我们来生成 signature

const crypto = require("crypto");
const sign = crypto.createSign("SHA256");
const secret = `私钥,太长我就不贴出来了`; sign.write(header + "." + payload);
sign.end(); const signature = sign
.sign(secret, "base64")
// 在JWT库中,已经把这些字符过滤掉了
.replace(/=/g, "")
.replace(/\+/g, "-")
.replace(/\//g, "_"); console.log(signature);

到此,已经实现了如何生成一个 JWT 的 token.

它是如何做身份验证的?

首先,JWT 的 Token 相当是明文,是可以解密的,任何存在 payload 的东西,都没有秘密可言,所以隐私数据不能签发 token。

而服务端,拿到 token 后解密,即可知道用户信息,例如本例中的uuid

有了 uuid,那么你就知道这个用户是谁,是否有权限进行下一步的操作。

Token 的过期时间怎么确定?

payload 中有个标准字段 exp,明确表示了这个 token 的过期时间.

服务端可以拿这个时间与服务器时间作对比,过期则拒绝访问。

如何防止 Token 被串改?

此时 signature字段就是关键了,能被解密出明文的,只有headerpayload

假如黑客/中间人串改了payload,那么服务器可以通过signature去验证是否被篡改过。

在服务端在执行一次 signature = 加密算法(header + "." + payload, 密钥);, 然后对比 signature 是否一致,如果一致则说明没有被篡改。

所以为什么说服务器的密钥不能被泄漏。

如果泄漏,将存在以下风险:

  • 客户端可以自行签发 token
  • 黑客/中间人可以肆意篡改 token

安全性相关

如果加强 JWT 的安全性?

根据我的使用,总结以下几点:

  1. 缩短 token 有效时间
  2. 使用安全系数高的加密算法
  3. token 不要放在 Cookie 中,有 CSRF 风险
  4. 使用 HTTPS 加密协议
  5. 对标准字段 iss、sub、aud、nbf、exp 进行校验
  6. 使用成熟的开源库,不要手贱造轮子
  7. 特殊场景下可以把用户的 UA、IP 放进 payload 进行校验(不推荐)

JWT的使用流程的更多相关文章

  1. ASP.NET Core Web API中带有刷新令牌的JWT身份验证流程

    ASP.NET Core Web API中带有刷新令牌的JWT身份验证流程 翻译自:地址 在今年年初,我整理了有关将JWT身份验证与ASP.NET Core Web API和Angular一起使用的详 ...

  2. Django的JWT机制工作流程

    https://blog.csdn.net/bin_1022/article/details/81278513 django-rest-framework-jwt token 怎么解码得到用户名? d ...

  3. Hacking JWT(JSON Web Token)

    0x01 JWT工作流程 JSON Web Token(JWT)是一个非常轻巧的规范. 这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息. JWT常被用于前后端分离,可以和Restful ...

  4. Java JWT: JSON Web Token

    Java JWT: JSON Web Token for Java and Android JJWT aims to be the easiest to use and understand libr ...

  5. [转]Node.js 应用:Koa2 使用 JWT 进行鉴权

    本文转自:https://www.cnblogs.com/linxin/p/9491342.html 前言 在前后端分离的开发中,通过 Restful API 进行数据交互时,如果没有对 API 进行 ...

  6. Node.js 应用:Koa2 使用 JWT 进行鉴权

    前言 在前后端分离的开发中,通过 Restful API 进行数据交互时,如果没有对 API 进行保护,那么别人就可以很容易地获取并调用这些 API 进行操作.那么服务器端要如何进行鉴权呢? Json ...

  7. 第九节:JWT简介和以JS+WebApi为例基于JWT的安全校验

    一. 简介 1. 背景 传统的基于Session的校验存在诸多问题,比如:Session过期.服务器开销过大.不能分布式部署.不适合前后端分离的项目. 传统的基于Token的校验需要存储Key-Val ...

  8. 漫谈JWT

    一.JWT简介[对于了解JWT的童鞋,可以直接跳到最后] 咱们就不弄那些乱七八糟的概念,就简单点说一下JWT是什么.有什么和能干什么 1. JWT概念和作用 JWT全称为json web token, ...

  9. 理解JWT(JSON Web Token)认证及python实践

    原文:https://segmentfault.com/a/1190000010312468?utm_source=tag-newest 几种常用的认证机制 HTTP Basic Auth HTTP ...

随机推荐

  1. from appium import webdriver 报错

    from appium import webdriver 报错 看看你的文件是不是就叫appium

  2. Avito Cool Challenge 2018-A. Definite Game(思维题)

    time limit per test 1 second memory limit per test 256 megabytes input standard input output standar ...

  3. zabbix agent 配置

    http://blog.csdn.net/z644041867/article/details/76618644 https://www.cnblogs.com/miclesvic/p/6144924 ...

  4. 洛谷P3959 宝藏(模拟退火乱搞)

    题意 题目链接 题面好长啊...自己看吧.. Sol 自己想了一个退火的思路,没想到第一次交85,多退了几次就A了哈哈哈 首先把没用的边去掉,然后剩下的边从小到大排序 这样我们就得到了一个选边的序列, ...

  5. 像音乐播放App一样移动背景

    如果你经常听歌,你会发现歌曲app的背景会随着音乐移动的,从左到右或者从上到下,这种动画虽然简单,但是这里有一个技巧.如果你还不明白这种动效看看下面的demo (更多详细请参考:https://git ...

  6. 读Linear Algebra -- Gilbert Strang

    转眼间我的学士学位修读生涯已经快要到期了,重读线性代数,一是为了重新理解Algebra的的重要概念以祭奠大一刷过的计算题,二是为了将来的学术工作先打下一点点(薄弱的)基础.数学毫无疑问是指导着的科研方 ...

  7. uvm_mem_mam——寄存器模型(十三)

    有了存储器模型,再来看看存储器的管理 //------------------------------------------------------------------------------ ...

  8. Eclipse IDE配置PHP开发、调试环境

    前言 使用java语言开发的朋友想必对Eclipse开发工具已经不陌生了,那么Eclipse作为java主流的开发工具,是否能够开发PHP项目呢?答案如你所想,肯定是可以的!以下就是该IDE下如何配置 ...

  9. SQL SERVER之填充因子

    建SQL SERVER索引的时候有一个选项,即Fillfactor(填充因子). 这个可能很少人会去注意它,但它也是比较重要的.大家可能也都知道有这个东西,但是如何去使用它,可能会比较迷糊.另外,即使 ...

  10. (转载)Newtonsoft.Json使用总结

    Newtonsoft.Json使用总结 初识JSON.......................................................................... ...