当 Web 成为人们可以实际执行有意义的任务(如银行或工作)的地方时,隐含的需求就是对使用服务的人进行身份验证。
毕竟,我们不能只相信使用这些服务的人使用了它们。必须实施某种方式,让人们可以证明他们是他们所说的那个人。
最初,这就像用户名和密码组合一样简单。理论上,您是唯一知道您的密码的人。
身份鉴权
通常,您会使用您的凭证在网页上填写表单,然后点击提交。您的详细信息将通过 HTTP 发送 POST 请求到服务器,服务器将检查您的密码是否与存档的内容匹配,然后向您发放一个 cookie。
该 Cookie 将包含您的Token,并将与每个后续请求一起提交,以便服务器知道在每个后续请求中信任您。
如果需要在会话期间存储数据,例如您选择的数据或首选项,则可以将其存储在session中。有时,这被称为 sessionizing 您的数据。
在用户session中存储数据是存储和检索瞬态信息的一种简单且廉价的方法。
不幸的是,这种方法有几个缺点:
- 将您的用户名和密码发布到服务器,经常发生在不安全的 HTTP 请求上。在这种情况下,您的用户名和密码可以被任何人或您与服务器之间的任何内容直接从 HTTP的POST 请求中读出
- 将您的密码(本应是秘密的)发送到远程服务器并不是一个好主意。如果远程服务器遭到入侵,那么不良行为者将可以轻松访问发送给他们的这些凭据,然后可以自由地在其他银行网站或电子邮件提供商上试用这些凭据。因为密码经常被重复使用,所以这将非常有效
- 很多时候,密码会以明文形式存储,并以这种格式在服务器上进行比较,这对于黑客或其他可以检索用户名/密码组合宝库的不良行为者来说显然是一个相当大的蜜罐
至于在用户的session中存储数据,如果有一台服务器为应用程序提供服务,则此方法有效。当服务器跨越多个服务器时,所有服务器都必须保持其会话同步。
为此,人们设计了许多方法,例如将会话数据存储在数据库服务器上或某种内存存储中,但从长远来看,更好的解决方案是简单地完全删除会话。
依赖服务器上的可变数据存储不是一个好主意,理想情况下,使用者应该拥有应用程序运行所需的所有信息。
JWT
回到我们最初的例子,当我们看另一个人时,我们可以快速评估我们是否认识他们。根据我们是否了解他们,我们可以向他们提供有关我们生活和发生的事情的更多细节。
但我们不能指望总是能够看到信任他们的人。有时,我们可以在不见对方的情况下进行信任交换。
例如,当您上班时,您可能有一张刷卡,您可以在读卡器上刷卡。读卡器会读取您的卡,如果卡有效,则通过身份验证。这更好,因为您不必向任何人透露您的密码或任何对您来说保密的事情。
我们知道使用读卡器进入建筑物是安全的,因为信任链是完整的。读卡器是由值得信赖的公司发行的,您的门禁卡也可能由他们发行。我们可以把卡带走,在某个地方存放很长时间,当我们回来的时候,它仍然是值得信赖的。
如果有人打开卡并更改或更改它以试图给他们更多的访问权限,他们反而会损坏卡,它就会停止工作。
JWT 有点像这样。它们由三个独立元件组成:
- 描述令牌中的信息以及正在使用的加密的标头
- payload
- 证明 Token 可靠的签名
计算签名的算法是 header 和 payload 的加密结果与 secret 相结合。因此,如果header或payload发生更改,则签名将无效,并且内容将不受信任。
因此,即使我们在 JWT 中包含数据以表明用户是管理员,只要签名得到正确验证,我们就可以确保 JWT 仍然是该事实的正确表示。因为公众无法访问我们的签名密钥,所以我们可以确定唯一可以颁发该 JWT 的实体是我们的服务器。
我们可以在 https://jwt.io 这样的网站上轻松查看 JWT 令牌的内容。
携带您的令牌
现在我们有了令牌,下一个问题应该是我们如何将其呈现给服务器。以前的身份验证方法需要基于 Cookie 的身份验证。但是,通常使用我们的 JWT 令牌,我们会将它们与受保护的资源一起呈现给服务器,以便我们可以被授予访问权限。
这意味着在我们的 HTTP 方法(POST、GET 等)中,我们还将包含一个 Authorization 值。它通常如下所示:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.uXrIhrveuvbR4tD1ULholQObboLVC-wIfJOEVElEzcs
使用此令牌,服务器可以在分析令牌中的声明之前验证令牌。但是,索赔包含哪些内容?
声明只是 JWT 中包含特定令牌信息的字段。它们分为三类:注册、公共和私有。
已注册的声明是可在 JWT 令牌中使用的标准字段。它们不是必需的,但通常会在大多数代币中找到。
公共声明由应用程序定义,并与正在使用的应用程序的数据相关。
私有声明是用于在实现之间共享信息的自定义声明,但只有涉及的实体知道声明是什么以及它们的工作原理。
OAuth 2.0 与此有何关系?
我们详细介绍了什么是 JWT、它们的工作原理以及我们可以信任它们的原因。通常,它们与 OAuth 一起被提及,有时人们会尝试比较它们或尝试选择一个而不是另一个。
但是,它们没有可比性,而是 OAuth 通常使用 JWT 令牌来传输与其相关的信息。由于 JWT 是一种以防篡改方式传输重要数据的可靠方法,因此它们是在 OAuth 2 中使用的不错选择。
例如,OAuth 发送的 ID 令牌始终作为 JWT 发送。当同时发送访问令牌时,它通常也作为 JWT 发送。OAuth 使用 JWT 来实现与其相关的各种流。
另一种类型的令牌是 Bearer 令牌,它与 Authorization 标头中的每个 HTTP 方法一起发送。它充当安全资源,指示令牌的持有者有权访问相关资源。因此,请务必仅将 Bearer 令牌发送到需要它的受保护终端节点。
OAuth 可以使用任何其他可行的系统来传输其令牌,但是因为 JWT 是一个标准,所以这就是正在使用的系统。事实上,OpenID Connect 正在扩展 JWT。
结论
JWT 和 OAuth 是安全的异步 Web 的关键部分。正如我们在本文中所看到的,他们不是竞争对手,您也不应该(或您可以)选择一个而不是另一个。JWT 以 OAuth 的补充能力存在,并且在将可信数据从 A 点移动到 B 点方面做得非常出色。