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

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

浅显易懂讲解如何用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)被发送的。如下所示:

  1. Authorization:Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U

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

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

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

  1. // Header
  2. eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
  3. // Payload
  4. eyJzdWIiOiIxMjM0NTY3ODkwIn0
  5. // Signature
  6. dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U

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

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

头部

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

  1. {
  2.   “alg”:”HS256″,
  3.   “typ”:”JWT”
  4. }

有效载荷

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

  1. {
  2.   “userId”:”1234567890”
  3. }

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

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

哈希算法

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

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

  1. 4ae7c3b6ac0beff671efa8cf57386151c06e58ca53a78d83f36107316cec125f

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

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

JWT签名

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

  1. HMACSHA256(
  2.   base64UrlEncode(header) + “.” + base64UrlEncode(payload),
  3.   “secret string”
  4. );

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

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

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

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

问:什么是密钥?

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

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

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

身份验证过程

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

登录

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

  1. logincontrol.js:
  2. if (passwordCorrect) {
  3.   user.token = generateToken(user.id);
  4.   user.save();
  5. }

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

logincontrol.js:

  1. if (passwordCorrect) {
  2.   user.token = generateToken(user.id);
  3.   user.save();
  4.   res.headers(“authorization”,`Bearer ${token}`).send();
  5. }

验证请求

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

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

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

authMiddleware.js:

  1. const token = req.header.token;
  2. const payload = decodeToken(token);
  3. const user = User.findById(payload.id);
  4. if (user.token = token) {
  5.   // Authorized
  6. } else {
  7.   // Unauthorized
  8. }

注销

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

logoutcontrol.js:

  1. user.token = null;
  2. user.save();

总结

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

  • Jwt.io – https://jwt.io/
  • 什么是JSON Web Token?- https://robmclarty.com/blog/what-is-a-json-web-token

极牛网精选文章《浅显易懂讲解如何用JWT来加固API》文中所述为作者独立观点,不代表极牛网立场。如若转载请注明出处:https://geeknb.com/7812.html

(0)
打赏 微信公众号 微信公众号 微信小程序 微信小程序
主编的头像主编认证作者
上一篇 2019年5月10日 上午8:19
下一篇 2019年5月10日 上午10:26

相关推荐

发表回复

登录后才能评论
扫码关注
扫码关注
分享本页
返回顶部