REST Web 服务的身份验证

Posted

技术标签:

【中文标题】REST Web 服务的身份验证【英文标题】:Authentication for REST web services 【发布时间】:2013-11-12 08:06:03 【问题描述】:

我开始设计 REST Web 服务,但不清楚最佳的身份验证方法。该服务将允许个人用户访问/管理他们自己的数据,因此需要某种类型的用户身份验证。我一直在研究这些选项:

OAuth

OAuth 似乎更多的是关于授权而不是身份验证。我计划在服务中本地处理授权,所以我不是在寻找解决方案。但是,OAuth 是否也适用于身份验证?

OpenID

OpenID 确实提供了一种身份验证解决方案,但这更多是为了允许用户使用他们的第 3 方凭据(Google、Yahoo 等)。虽然我愿意支持这一点,但这不是我主要关心的问题,我肯定会允许用户使用本机凭据(电子邮件/密码)进行注册。

HTTP 基本身份验证

这很容易实现,但据我了解,这可能不是一个非常安全的方法。此外,似乎每次访问都需要交换凭据,但我希望用户进行一次身份验证,然后通过会话令牌继续访问。

自定义身份验证

基本上,推出我自己的登录/令牌生成服务,并需要一个有效的令牌来访问所有其他资源(显然,一切都将通过 SSL)。


除了创建 Web 服务之外,我还将构建一个代表用户使用这些服务的客户端(Web)应用程序,但我不希望该应用程序必须存储用户信息/凭据/等等。所以,是这样的:

用户(使用电子邮件/密码或第 3 方凭据进行身份验证) --> Web 应用程序(使用应用程序 ID 进行身份验证) --> 网络服务

再一次,我希望其他人也可以构建客户端,因此中间层可以是任何 3rd 方应用程序:

用户(使用电子邮件/密码或第 3 方凭据进行身份验证) --> 3rd 方应用程序(使用应用程序 ID 进行身份验证) --> 网络服务

我的最高要求是:

安全(显然) 本机凭据 支持第 3 方凭据(Google、Yahoo、LinkedIn 等) 支持多个客户端(Web 应用、移动应用、第 3 方应用等) 客户端凭据(只是一个应用 ID?) 登录会话过期 不需要授权

所以,我的问题是,基于上述(如果这太模糊,请告诉我),是否有“最佳”方法? OAuth 或 OpenID 是否合适,还是我把它弄得太复杂了,而应该只使用我自己的身份验证?

编辑:

我认为我需要实现以下内容:

1) 原生凭证/令牌(基于 SSL 的 HTTP 基本身份验证?)

2) 一个 OpenID“依赖方”,允许我的 api 使用托管在其他地方的 OpenID(即“支持第 3 方凭据”)

3) 一个 OAuth“消费者”,允许我的 api 访问第 3 方服务(例如访问用户的 LinkedIn 个人资料)。

4) 一个 OpenID“提供者”,允许人们在别处使用 api 的原生 ID(可选)

5) 允许第三方应用代表用户访问我的 API 的 OAuth“提供者”(可选)

这看起来是对的,还是我让它变得比需要的更复杂?

【问题讨论】:

推荐文章best practices for a pragmatic restful api,你也可以看看其他人是如何实现的,比如github “只是滚动我自己的身份验证”,永远不要这样做。滚动您自己的身份验证是软件工程最佳实践的对立面。人们毕生致力于解决“我们如何安全地验证用户身份?”问题。 【参考方案1】:

您可以考虑使用 JWT(JSON Web 令牌)参见 JWT draft rfc。它肯定会满足您的安全和会话到期要求。然而,作为一个草案标准,它现在不太可能被广泛使用,这可能很快就会改变,因为 JWT 是 OAuth 2.0 的一部分。 JWT 很容易在大多数语言中实现,并且已经有很多库。作为一个简单的解释,一个 JWT 令牌由 3 部分组成,头、正文和签名。标头和正文是经过 basee64url 编码的 json 对象(字母与 base64 的最后两个字符不同),然后使用 HMAC256(或标头中指定的其他算法)签名,RFC 解释了如何准确生成此签名。您可能想查看此online token generator。

JWT 对 http 标头和查询参数友好。

【讨论】:

这个以及这里的许多其他答案,每一个都涉及到一块拼图。不过,没有一个答案包含完整的答案。 这是迄今为止我找到的最佳答案。它提倡使用具有(截至 2016 年)实现它的现有库的标准 (JWT)。这意味着,希望利用 JWT 的人不必“推出自己的”实现。【参考方案2】:

要考虑的一个不错的选择是“共享密钥身份验证”。这是 Amazon Web 服务和 Windows Azure 存储服务使用的身份验证类型。我们在开发的 REST 服务中使用了共享密钥认证。您可以在 Google 中快速搜索“共享密钥身份验证”,您将获得很多详细信息。

我为此写了一篇博文here。

高级步骤是:

    客户端组合了一组由 REST 服务定义的唯一数据(元素)。 使用只有客户端和 REST 服务知道的密钥签署此组合数据 将此签名作为 HTTP 标头的值发送到 REST 服务 REST 服务计算签名的方式与客户端完全相同 将客户端发送的签名与计算的签名进行比较,如果相同,则假定其为有效请求,否则拒绝该请求

【讨论】:

供参考:AWS Authenticating Requests【参考方案3】:

我的建议是验证第一个请求,然后设置会话令牌。

前端应用程序将存储令牌并将其提供给每个后续请求。

令牌会有过期时间。令牌在一定时期内不使用就会过期。

令牌可以与原始 IP 地址关联以增加安全性。

令牌可以作为 cookie 传输,也可以作为 URL 中的查询参数之一传输。

如果 SSL 客户端身份验证的麻烦是可以接受的,您可以使用相互 SSL 身份验证。必须为每个客户端提供服务器信任的证书。如果您必须区别对待客户,它可以是相同的证书,也可以是不同的证书。

【讨论】:

@arunasr 但是会话令牌和用户名/密码有什么不同?它们都是用户的唯一 ID @Shawn username/pwd 是用户的身份验证凭据。会话令牌是一次性可过期的随机数据。为什么每次都可以发送用户名/密码时需要令牌?这样您就不必多次存储和传输用户凭据。用户名和密码很敏感,应该使用昂贵的散列算法进行保护。您希望尽可能少地存储和传输它们,以防第三方获取它们。会话令牌是临时的,即使被拦截也不会永久损害安全性。 赞成,因为它解释了一种简单的工作方式,无需使用一些庞大且难以理解的 3rd 方解决方案。因此,它可以让人们了解幕后发生的事情。但我还有一个问题:如果您要为 GUI(面向演示的)Web 应用程序实现身份验证,这种机制本质上不就是您会做的吗?所以本质上,您可以使用相同的机制来保护面向服务 (REST) 和面向表示(例如 JSF)的 Web 应用程序? 另外,这需要 REST 应用程序的后端数据库将会话令牌保存在服务器端,对吗?或者我猜它们也可以保存在内存中(例如,在使用 setAttribute 的 servlet 上下文中)以及如果音量低? 是的,您需要将会话信息保存在所有负载共享服务器都可以访问的位置,如果您不希望会话在服务器重新启动和负载共享后继续存在,可以将其保存在内存中。我不认为记忆是一个考虑因素,除非你的会话非常长。【参考方案4】:

根据您的要求,我认为OAuth 2.0 实际上可能是一个有趣的选择。 OAuth 确实是一种授权协议,但它也为Authenticates 客户端提供了clientIdclientSecret。您可以使用Client Credential Flow 并选择不包含Refresh Token,这样用户就有了Access Token,它会在一定时间后过期。由于 OAuth 是一种广泛使用的协议,它们已经有许多客户端和服务器端库供您和您的客户使用。

如果您认为 OAuth 对您的应用程序来说过于繁重或过于复杂,我可能会坚持使用 Basic Authentication 而不是 HTTPS。但正如我在另一个类似问题的答案中所说,我永远不会发明自己的身份验证机制。

有关更多信息,您还可以查看我之前针对类似问题提供的其他答案:https://***.com/a/15003777/849741

【讨论】:

感谢 Jos 的回复。但是,我不需要同时实现 OAuth OpenID 吗?在我看来,我的第三个要求“支持第三方凭据”需要 OpenID,这不是真的吗?【参考方案5】:

您可以使用 HTTP 基本身份验证,其中传输的密码实际上不是密码而是令牌,客户端在不同的资源请求中获取,他/她/它必须提供他/她/它的密码一次,然后只有一次(甚至可能通过不同的渠道)。这不能保护中间人攻击(因为没有消息签名),但想法是,您始终可以要求客户端以某种方式生成动态令牌(即在您自己的身份验证服务上),然后让它发送该令牌作为密码替换,因此实际密码不会不断地通过网络传输。 是的,这看起来像是“自定义身份验证解决方案”之一,但实际上并不是因为您可以在令牌密码上施加您想要的任何规则,例如使用签名令牌作为会话绑定或重新计算的密码在每个请求上(不共享任何秘密),以便服务器可以验证消息 - 无论您需要什么。这个想法是将验证令牌作为 HTTP 基本身份验证请求的“密码”发送,而不依赖于更复杂的协议,同时不排除这些协议(由您选择)。

【讨论】:

【参考方案6】:

我已经实现并作为开源发布了一个允许身份验证的基本服务,如果需要,它可以很容易地更改为允许 3 元组登录。它大约有 2 年的历史,并且在 Spring 上用 Java 编写,因此您可能想重新考虑该技术,但它确实有效,您可以了解它是如何完成的基本概念。找到它here on google,或关注my blog posts。请注意,该应用程序不再在 cloudbees 上加载,但如果您在您的帐户中设置它,一切都应该没问题。

【讨论】:

【参考方案7】:

我建议将 Spring Boot 用于您的 RESTful Web 服务,因为这样您就可以使用他们的 Spring Security 根据他们的模板实现您自己的自定义身份验证。您可以通过分别扩展或实现其基本安全类和接口来实现您自己的自定义身份验证。如果需要,您还可以选择合并您在 Spring Boot 中列出的其他身份验证机制。

【讨论】:

【参考方案8】:

OAuth 2.0 如果您只需要授权,可以使用。您可以使用OpenID Connect,它提供身份验证并支持OAuth2.0进行授权。对于 OepnID Connect,如果您需要自己设置服务,有许多认证产品可用,也有许多在线服务可用。

【讨论】:

以上是关于REST Web 服务的身份验证的主要内容,如果未能解决你的问题,请参考以下文章

如何在 REST Web 服务中验证用户身份?

REST Web 服务身份验证令牌实现

使用 ServiceStack 使用 REST Web 服务时的用户身份验证

如何使用 oauth2 通过 REST Web 服务进行身份验证

基于 REST 的 Web 应用架构的身份验证

为用户和身份验证使用解析服务器并调用其他内部 REST Web 服务