REST接口安全认证方式对比:API Key vs OAuth令牌 vs JWT

REST(Representational State Transfer)服务最初是作为一种极其简化的Web服务方法开始的。我们可以在纯文本文件中描述REST服务,并使用我们想要的任何消息格式,例如JSON,XML等。如果通过构建可以读取,写入和删除用户数据的API调用,使得API成为产品的强大扩展,几乎肯定是需要身份验证的。

下面我们将介绍三种流行的身份验证方法:API密钥,OAuth访问令牌和JSON Web令牌(JWT)。我们将介绍每种方法的使用方法以及如何进行选择。

API密钥:非常适合开发人员快速入门

在现代Web API的早期阶段,API密钥就是我们所拥有的。它可能仍然是最常见的身份验证方法,也是许多开发人员在限制或跟踪API流量时的优先考虑方法。API密钥的最大优点是简单。您只需登录服务,找到您的API密钥(通常在设置界面中),然后将其复制在应用程序中使用,在浏览器中进行测试,或与一些API请求工具一起使用。然而,除了提供简单性之外,API密钥还具有安全性和用户体验方面的缺点。

通常,API密钥可以完全访问API可以执行的每个操作,包括写入新数据或删除现有数据。如果您在多个应用中使用相同的API密钥,则被破坏的应用可能会损坏用户的数据,而无法轻松停止该应用。有些应用程序允许用户生成新的API密钥,甚至还有多个API密钥,可以选择撤销可能落入坏人手中的API密钥。更改API密钥的能力削弱了安全性缺点。

许多API密钥作为URL的一部分在查询字符串中发送,这使得很容易被不应该访问它的人发现。更好的选择是将API密钥放在Authorization标头中。事实上,这是标准性的建议:
Authorization: Apikey 1234567890abcdef

然而,在实践中,API密钥会出现在各种各样的地方:

  • 授权标题
  • 基本认证
  • 主体数据
  • 自定义数据头
  • 请求参数

API密钥的用户体验也是需要考虑的因素。当API的用户只是开发人员时,API密钥才有意义。但是,随着开发人员为自己创建工具,他们开始与其他人共享它们。最终用户经常发现自己在API文档,注册和设置等地方搜索,只是为了找到工具所需的API密钥 - 通常甚至不知道API是什么。

OAuth令牌:非常适合访问用户数据

OAuth是使用API​​访问用户数据的更好方式。与API密钥不同,OAuth不需要用户通过开发人员门户进行探索。事实上,在最好的情况下,用户只需单击一个按钮即可让应用程序访问其帐户。OAuth,特别是OAuth 2.0,是幕后流程的标准,用于确保安全处理这些权限。

此规范的先前版本OAuth 1.0和1.0a比OAuth 2.0复杂得多。最新版本中最大的变化是不再需要使用哈希值对每个调用进行签名。最常见的OAuth实现使用这些令牌中的一个或两个:

  • 访问令牌:像API密钥一样发送,它允许应用程序访问用户的数据; 可选地,访问令牌可以到期。
  • 刷新令牌:可选地,是OAuth流的一部分,刷新令牌如果已过期则检索新的访问令牌。

与API密钥类似,您可以在很多地方找到OAuth访问令牌:查询字符串,标题和其他位置。由于访问令牌就像一种特殊类型的API密钥,因此最有可能放置它的是授权头,如下所示:
Authorization: Bearer 1234567890abcdef

访问和刷新令牌不应与客户端ID和客户端密钥混淆。这些值可能看起来像一个类似的随机字符集,用于协商访问和刷新令牌。

与API密钥一样,任何拥有访问令牌的人都可能会调用有害操作,例如删除数据。但是,OAuth对API密钥提供了一些改进。对于初学者来说,访问令牌可以绑定到特定的范围,这限制了应用程序可以访问的操作类型和数据。此外,与刷新令牌相结合,访问令牌将过期,因此负面影响可能会产生有限的影响。最后,即使不使用刷新令牌,仍然可以撤销访问令牌。

JWT令牌:非常适合限制数据库查找

API密钥和OAuth令牌始终用于访问API,而JSON Web令牌(JWT)可用于许多不同的场景。实际上,JWT可以存储任何类型的数据,这是与OAuth结合使用的优势。使用JWT访问令牌,需要的数据库查找次数要少得多,同时仍然不会影响安全性。

JWT主要包含三个部分之间用英语句号'.'隔开:

  1. Header 头部
  2. Payload 负载
  3. Signature 签名

注意:顺序是 header.payload.signature

头部(Header)中通常包含了两部分:token类型和采用的加密算法。将内容进行base64编码,可以得到JWT的头部。
负载(Payload)为JWT的第二部分。JWT的标准所定义了一下几个基本字段

  1. iss: 该JWT的签发者
  2. sub: 该JWT所面向的用户
  3. aud: 接收该JWT的一方
  4. exp(expires): 什么时候过期,这里是一个Unix时间戳
  5. iat(issued at): 在什么时候签发的

除了标准定义的字段外,我们还可以定义一些我们在业务处理中需要用到的字段。最后需要将负载这整个部分进行base64编码。
签名(Signature )其实是对JWT的头部和负载整合的一个签名验证,然后对签名内容进行base64编码得到最终的签名。

最终的JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJob21lcGFnZSI6Imh0dHBzOi8vemFwaWVyLmNvbSIsInRhZ2xpbmUiOiJaYXBpZXIgbWFrZXMgeW91IGhhcHBpZXIiLCJmb3JtIjoiaHR0cHM6Ly96YXBpZXIudHlwZWZvcm0uY29tL3RvL0hkRVk0eiJ9.E3EtYy2y7BRn4eS0RIyDAAh-KAsa6dVV91ULbBJCRJw

您可以避免数据库查找,因为JWT包含确定访问标识和范围所需的数据。JWT还包含使用JWT数据计算的签名。使用您用于生成JWT的相同密钥,您可以计算自己的签名版本并进行比较。此计算比在数据库中查找访问令牌以确定它属于谁以及它是否有效要高效得多。

与OAuth访问令牌一样,JWT令牌应该在Authorization标头中传递:
Authorization: Bearer
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJob21lcGFnZSI6Imh0dHBzOi8vemFwaWVyLmNvbSIsInRhZ2xpbmUiOiJaYXBpZXIgbWFrZXMgeW91IGhhcHBpZXIiLCJmb3JtIjoiaHR0cHM6Ly96YXBpZXIudHlwZWZvcm0uY29tL3RvL0hkRVk0eiJ9.E3EtYy2y7BRn4eS0RIyDAAh-KAsa6dVV91ULbBJCRJw

不通过每次调用查找访问令牌的缺点是JWT无法撤销。因此,您需要将JWT与刷新令牌和JWT到期结合使用。每次API调用时,您都需要检查JWT签名并确保仍然未过期。

应该使用哪种?

如您所见,这三个选项并不相互排斥。事实上,有些API可以同时使用这三种。或者每个都可以独立使用。
如果您希望开发人员构建不需要访问多个用户数据的内部应用程序,请使用API​​密钥。
如果您希望用户轻松地为应用程序提供授权而无需共享私有数据或挖掘开发人员文档,请使用OAuth访问令牌。
如果要限制数据库查找并且不需要立即撤消访问权限,请将JWT与OAuth配合使用。

注意:保持API密钥简单性同时还支持OAuth的一种方法是创建一次性令牌以供内部使用。

推荐阅读更多精彩内容