前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >浅显易懂讲解如何用JWT来加固API

浅显易懂讲解如何用JWT来加固API

作者头像
Lemon黄
发布2019-12-13 18:29:40
1K0
发布2019-12-13 18:29:40
举报
文章被收录于专栏:Lemon黄Lemon黄

您一定听说过JSON Web Token(JWT)吧? 它是当前用来保护API的先进技术之一。与大多数安全概念与技术一样,我们在准备使用它之前,了解其工作原理是非常必要且重要的。当然,过于专业和技术性的JWT解释可能会让您觉得费解,甚至感到头痛。那么让我试着用一种比较浅显易懂的方式,向您阐述JWT是如何加固API的吧。

API身份验证

不言而喻,在复杂的网络环境中,我们需要对各种API资源实施访问限制。例如,我们不希望某个用户能够更改另一个用户的密码。那么,我们就需要该用户以提交其ID和密码的方式,来保护和加固目标资源。换句话说:我们需要对他们进行身份验证。

而在实际应用中,我们保护HTTP类API的难点在于:各种请求是无状态的。也就是说:API无法知道任意两个请求是否来自同一个用户。有人可能会追问:我们为什么不能要求用户在每次调用API时,都提供他们的ID和密码呢?答案是:因为这样会给用户带来极差的访问体验。

JSON Web Token

因此,我们需要的是:用户只用一次性提供信任凭据,而在后续的请求中,服务器会以另一种方式进行用户身份的识别。基于这种思想,JSON Web Token应运而生。

当然,如果您是一位爱好钻研的学霸,那么您可以通过链接:https://robmclarty.com/blog/what-is-a-json-web-token,来对JSON Web Token的工作原理进行全面深入的参悟。

在此让我们想象一下:如果您打算入住一家酒店,那么“令牌”就是允许您进入自己房间、以及酒店内其他设施的安全门卡,显然您不能进入其他人的房间。而且在退房的时候,您需要退还门卡,即:注销。

令牌的结构

通常情况下, JSON Web Token是通过各种HTTP请求的头部(header)被发送的。如下所示:

代码语言:javascript
复制
Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U

可见,令牌就是"Authorization:Bearer"的后面部分,隶属于HTTP的头部信息。

上述信息虽然显得比较凌乱,不过它包含了如下部分:

首先,令牌由三个不同的字符串所组成,它们分别以点号隔开。这三个字符串使用了base 64编码,分别对应头部(header)、有效载荷(payload)和签名(signature),如下所示:

代码语言:javascript
复制
// Header  
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 
// Payload 
eyJzdWIiOiIxMjM0NTY3ODkwIn0 
// Signature 
dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U 

注:base 64是一种转换字符串的方法,能够确保字符串在跨Web传输的过程中不会出现问题。由于它不是一种加密方法,因此任何人都可以很容易地对它进行解码,以查看原始数据。

下面,我们对上述字符串进行解码,以便更好地了解JWT的结构。

头部

通过解码令牌的头部,我们可以得到如下的元信息(meta information)。由于它对于我们理解整体的工作原理帮助不大,所以我们在此并不做详细解读。

代码语言:javascript
复制
{   "alg":"HS256",   "typ":"JWT" } 

有效载荷

有效载荷里的内容要丰富得多。您可以用它来包含任何自己需要传递的数据。在此,由于该令牌的目的是对API的访问进行身份验证,因此仅包含了用户的ID。

代码语言:javascript
复制
{   "userId":"1234567890" } 

值得注意的是:有效负载并不安全。任何人都可以通过解码令牌,来查看有效负载中的确切内容。因此,我们通常只包含ID,而不会包含诸如用户邮件内容等敏感的标识信息。

尽管该有效负载为API提供了识别用户所需的全部信息,但是它并不提供具体的身份验证方法。毕竟凭借这些信息,黑客足以能够轻松地找到用户的ID,并可伪造出令牌。因此,我们还需要有签名,而它才是令牌认证环节中的关键部分。

哈希算法

在开始解释签名的工作原理之前,我们需要先来了解一下什么是哈希算法。

首先,它是一个函数,可用来将目标字符串转换为另一种被称为哈希值(hash)的新字符串。例如,我们对字符串“Hello, world.”进行哈希操作,那么就能够得到如下经过了SHA256哈希算法的输出:

代码语言:javascript
复制
4ae7c3b6ac0beff671efa8cf57386151c06e58ca53a78d83f36107316cec125f 

注:哈希算法有许多种不同的类型,JWT常用的是SHA256。

而哈希的重要属性在于:我们无法使用哈希算法,通过哈希值来识别出原始的字符串。换句话说,我们无法凭借上述哈希值,直接计算或得出原始的字符串“Hello, world.”。从理论上说,根据哈希的复杂性,猜测出原始字符串是完全不可行的。

JWT签名

现在,让我们来看JWT令牌结构的第三个部分:签名。实际上,该部分是需要进行计算的。

代码语言:javascript
复制
HMACSHA256(   base64UrlEncode(header) + "." + base64UrlEncode(payload),   "secret string" ); 

我们下面来具体分析一下上述代码:

  • 首先,HMACSHA256是哈希函数的名称,它用到了两个参数:需要进行哈希的字符串和密钥(secret)。
  • 其次,这个需要进行哈希的字符串,是经过base 64编码过的头部和有效载荷。
  • 第三,密钥是一串任意数据,而且只有服务器知晓。

问:为什么要将头部和有效载荷添加到签名的哈希值中呢?

答:这样可以确保签名对于该特定令牌来说是仅有的。

问:什么是密钥?

答:让我们从如何伪造一个令牌的角度来回答该问题。我们之前说过,黑客无法从输出值来推导出经过哈希的输入信息。但是,由于签名中包括了头部和有效载荷,而这些都是公共的信息,因此如果黑客知道了哈希算法(这通常是在头部被指定的),那么就能够生成相同的哈希值。

可见,如果服务器掌握了某个非公开的密钥,并且将其包含在哈希处理的过程中,那么就能够防止黑客自行伪造并生成带有哈希值的令牌。同时,由于哈希值“掩盖”了各种原始信息,因此也就保证了密钥不会被黑客所发现。

注:将私有数据添加到哈希之中的过程,被称为加盐(salting),这使得破解令牌几乎是不可能的。

身份验证过程

至此,想必您已经理解了令牌的创建过程。那么,我们又该如何用它来验证用户的API呢?

登录

在用户登录时,系统会生成一个令牌,并将其与用户模型(model)一起存储在数据库中。

代码语言:javascript
复制
logincontrol.js: 
if (passwordCorrect) { 
  user.token = generateToken(user.id); 
  user.save(); 
} 

然后作为对于登录请求的响应,该令牌被添加到authorization的头部。

logincontrol.js:

代码语言:javascript
复制
if (passwordCorrect) { 

  user.token = generateToken(user.id); 

  user.save(); 

  res.headers("authorization",`Bearer ${token}`).send(); 

} 

验证请求

有了令牌,用户现在就可以将其添加到各种后续的请求中,以验明正身了。

而当服务器收到添加了身份信息的令牌请求后,会进行如下操作:

  • 对令牌进行解码,并从有效载荷中提取ID。
  • 使用此ID,在数据库中查找该用户的信息。
  • 将请求令牌与带有用户模型的存储令牌进行比较。如果匹配,则认定该用户的“合法”身份。

authMiddleware.js:

代码语言:javascript
复制
const token = req.header.token; 
const payload = decodeToken(token); 
const user = User.findById(payload.id); 
if (user.token = token) { 
  // Authorized 
} else { 
  // Unauthorized 
} 

注销

如果该用户要求注销,那么系统只需删除掉当前已添加到用户模型的令牌便可。由于用户手上的令牌及时失效了,因此如果他需要再次登录的话,应重新产生新的令牌。

logoutcontrol.js:

代码语言:javascript
复制
user.token = null; 
user.save(); 

总结

通过上面的逐步分析,希望您能够对于如何使用JSON Web Token来加固API,已经建立起了基本的概念。当然,该话题涵括的内容远不止这些,如果您有兴趣的话,可以通过如下链接进行扩展阅读:

  • Jwt.io - https://jwt.io/
  • 什么是JSON Web Token?- https://robmclarty.com/blog/what-is-a-json-web-token
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-11-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Lemon黄 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
多因子身份认证
多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档