协慌网

登录 贡献 社区

RESTful 身份验证

RESTful 身份验证是什么意思,它如何工作?我在 Google 上找不到很好的概述。我唯一的理解是您在 URL 中传递了会话密钥(记住的),但这可能是非常错误的。

答案

如何在 RESTful 客户端 - 服务器体系结构中处理身份验证存在争议。

通常,它可以通过以下方式在 HTTP 上的 SOA 中实现:

  • 通过 HTTPS 进行 HTTP 基本身份验证;
  • Cookies 和会话管理;
  • HTTP 标头中的令牌(例如OAuth 2.0 + JWT);
  • 使用其他签名参数的查询身份验证。

您必须调整甚至更好地混合使用这些技术,才能最好地匹配您的软件体系结构。

每个身份验证方案都有自己的 PRO 和 CON,具体取决于您的安全策略和软件体系结构的目的。

通过 HTTPS 进行 HTTP 基本身份验证

大多数 Web 服务都使用基于标准 HTTPS 协议的第一个解决方案。

GET /spec.html HTTP/1.1
Host: www.example.org
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

它易于实施,默认情况下在所有浏览器上都可用,但是存在一些已知的缺点,例如浏览器上显示的可怕的身份验证窗口将持续存在(此处没有类似 LogOut 的功能),服务器端的额外 CPU 消耗,以及用户名和密码(通过 HTTPS)传输到服务器的事实(在键盘输入期间让密码仅保留在客户端,并作为安全哈希存储在服务器上应该更为安全) 。

我们可能会使用摘要式身份验证 ,但它也需要 HTTPS,因为它容易受到MiMReplay攻击的影响,并且特定于 HTTP。

通过 Cookie 的会话

老实说,在服务器上管理的会话并不是真正的无状态。

一种可能性是将所有数据保留在 cookie 内容内。而且,根据设计,cookie 是在服务器端处理的(实际上,客户端甚至不尝试解释此 cookie 数据:它仅在每次后续请求时才将其交还给服务器)。但是此 cookie 数据是应用程序状态数据,因此客户端应在纯净的无状态环境中管理它,而不是服务器。

GET /spec.html HTTP/1.1
Host: www.example.org
Cookie: theme=light; sessionToken=abc123

cookie 技术本身是 HTTP 链接的,因此它不是真正的 RESTful,应该是独立于协议的 IMHO。它容易受到MiMReplay攻击。

通过令牌(OAuth2)授予

一种替代方法是在 HTTP 标头中放置一个令牌,以便对请求进行身份验证。例如,这就是OAuth 2.0 所做的。参见RFC 6749

GET /resource/1 HTTP/1.1
 Host: example.com
 Authorization: Bearer mF_9.B5f-4.1JqM

简而言之,它与 cookie 非常相似,并且会遇到相同的问题:不是无状态的,依赖于 HTTP 传输详细信息,并且存在许多安全漏洞 (包括 MiM 和 Replay),因此只能在 HTTPS 上使用。通常,将JWT用作令牌。

查询认证

查询身份验证包括通过 URI 上的一些其他参数对每个 RESTful 请求进行签名。请参阅此参考文章

本文对此进行了定义:

所有 REST 查询都必须通过使用私有证书作为签名令牌,对以小写字母顺序排序的查询参数进行签名来进行身份验证。 URL 编码查询字符串之前应先进行签名。

该技术也许与无状态架构更兼容,并且还可以通过轻量级会话管理(使用内存中会话而不是数据库持久性)来实现。

例如,这是来自上面链接的通用 URI 示例:

GET /object?apiKey=Qwerty2010

应该这样传送:

GET /object?timestamp=1261496500&apiKey=Qwerty2010&signature=abcdef0123456789

要签名的字符串是/object?apikey=Qwerty2010&timestamp=1261496500 ,签名是使用 API 密钥的私有组件的字符串的 SHA256 哈希。

服务器端数据缓存始终可以使用。例如,在我们的框架中,我们在 SQL 级别而不是 URI 级别缓存响应。因此,添加此额外参数不会破坏缓存机制。

有关基于 JSON 和 REST 的客户端服务器 ORM / SOA / MVC 框架中的 RESTful 身份验证的一些详细信息,请参阅本文 。由于我们不仅允许通过 HTTP / 1.1 进行通信,而且还允许通过命名管道或 GDI 消息(在本地)进行通信,因此我们尝试实现一种真正的 RESTful 身份验证模式,而不依赖于 HTTP 特定性(例如标头或 cookie)。

以后的注释 :在 URI 中添加签名可能被视为不正确的做法(例如,由于它将出现在 http 服务器日志中),因此必须加以缓解,例如通过适当的 TTL 来避免重播。但是,如果您的 http 日志受到威胁,则肯定会遇到更大的安全问题。

实际上, 针对 OAuth 2.0的即将到来的MAC 令牌认证相对于当前的 “令牌授予” 方案而言可能是巨大的改进。但这仍在进行中,并且与 HTTP 传输相关。

结论

值得总结的是,REST 实际上不仅基于 HTTP,即使实际上它也大多是通过 HTTP 实现的。 REST 可以使用其他通信层。因此,无论 Google 回答什么,RESTful 身份验证不仅是 HTTP 身份验证的同义词。它甚至根本不应使用 HTTP 机制,而应从通信层中抽象出来。而且,如果您使用 HTTP 通讯,那么借助 “ 让我们加密” 计划 ,您就没有理由不使用适当的 HTTPS,这是除了任何身份验证方案之外所必需的。

我怀疑人们是否热烈地喊着 “HTTP 身份验证”,是否曾经尝试过使用 REST 制作基于浏览器的应用程序(而不是机器对机器的 Web 服务)(无意冒犯 - 我只是认为他们从未遇到过麻烦) 。

我发现在用于生成可在浏览器中查看的 HTML 页面的 RESTful 服务上使用 HTTP 身份验证的问题是:

  • 用户通常会收到一个由浏览器制作的难看的登录框,这对用户非常不友好。您无法添加密码检索,帮助框等。
  • 注销或以其他名称登录是一个问题 - 浏览器将继续向站点发送身份验证信息,直到您关闭窗口
  • 超时很困难

这里有一篇非常有见地的文章可以解决这些问题,但这会导致很多特定于浏览器的 javascript 黑客,变通办法等。因此,它也不向前兼容,因此在发布新浏览器时将需要不断维护。我不认为设计简洁明了,再加上我觉得这是很多额外的工作和头痛的事情,只是为了让我可以热情地向我的朋友们展示我的 REST 徽章。

我相信 cookie 是解决方案。但是等等,饼干是邪恶的,不是吗?不,不是,经常使用 cookie 的方式是邪恶的。 Cookie 本身只是一条客户端信息,就像浏览器在您浏览时会跟踪的 HTTP 身份验证信息一样。而且,每次客户端请求时,这些客户端信息都会发送到服务器,就像 HTTP 身份验证信息一样。从概念上讲,唯一的区别是服务器可以将这部分客户端状态的内容作为其响应的一部分来确定。

通过使会话成为具有以下规则的 RESTful 资源:

  • 会话将密钥映射到用户 ID(以及超时的 last-action-timestamp)。
  • 如果存在会话 ,则表示该密钥有效。
  • 登录意味着发布到 / sessions,将新密钥设置为 cookie
  • 注销意味着 DELETEing / sessions / {key}(使用重载的 POST,请记住,我们是浏览器,并且 HTML 5 还有很长的路要走)
  • 通过在每次请求时将密钥作为 cookie 发送并检查会话是否存在和有效来完成身份验证

现在,与 HTTP 身份验证的唯一区别在于,身份验证密钥是由服务器生成的,并发送给客户端,客户端不断将其发送回去,而不是由客户端根据输入的凭据来计算它。

converter42 补充说,在使用 https(我们应该这样做)时,重要的是,将 cookie 设置为安全标志,以便永远不要通过非安全连接发送身份验证信息。好点,我自己没看过。

我认为这是一个行之有效的解决方案,但我必须承认,我还不足以让安全专家来确定此方案中的潜在漏洞 - 我所知道的是,数百个非 RESTful Web 应用程序使用的本质上相同登录协议(PHP 中的 $ _SESSION,Java EE 中的 HttpSession 等)。 Cookie 标头的内容仅用于寻址服务器端资源,就像可以使用接受语言来访问翻译资源等一样。我觉得是一样的,但也许其他人不是吗?你们觉得怎么样?

这里的好人已经对这个话题说了足够多的话。但是,这是我的 2 美分。

有两种交互方式:

  1. 人机(HTM)
  2. 机器对机器(MTM)

机器是共同的分母,表示为 REST API,而参与者 / 客户端是人还是机器。

现在,在真正的 RESTful 架构中,无状态的概念意味着必须为每个请求提供所有相关的应用程序状态(即客户端状态)。所谓相关,是指 REST API 处理请求和提供适当响应所需要的任何内容。

当我们在人机应用程序的上下文中考虑这一点时,如 Skrebbel 所指出的,“基于浏览器的浏览器”,这意味着在浏览器中运行的(网络)应用程序将需要随每个请求发送其状态和相关信息。它使用后端 REST API。

请考虑以下因素:您拥有 REST API 的数据 / 信息平台公开资产。也许您有一个可以处理所有数据多维数据集的自助式 BI 平台。但是,您希望您的(人类)客户通过(1)Web 应用程序,(2)移动应用程序和(3)某些第三方应用程序访问此文件。最后,即使是 MTM 链,也导致了 HTM - 对。因此,人类用户始终处于信息链的顶端。

在前两种情况下,您需要进行人机交互,而信息实际上是由人类用户使用的。在最后一种情况下,您有一个使用 REST API 的机器程序。

身份验证的概念全面适用。您将如何设计它,以便以统一,安全的方式访问您的 REST API?我看到的方式有两种:

方式一:

  1. 首先,没有登录。每个请求都执行登录
  2. 客户端随每个请求发送其标识参数 + 请求特定参数
  3. REST API 接收它们,转过身,ping 用户存储(无论是什么)并确认身份验证
  4. 如果建立了身份验证,则为请求提供服务;否则,拒绝使用适当的 HTTP 状态代码
  5. 对目录中所有 REST API 的每个请求重复上述操作

方式 2:

  1. 客户端以身份验证请求开始
  2. 登录 REST API 将处理所有此类请求
  3. 它接受身份验证参数(API 密钥,uid / pwd 或您选择的任何内容),并根据用户存储(LDAP,AD 或 MySQL DB 等)验证身份验证
  4. 如果通过验证,则创建一个身份验证令牌,并将其交给客户 / 呼叫者
  5. 然后,调用方将此身份验证令牌 + 请求特定的参数以及每个后续请求发送给其他业务 REST API,直到注销或租约到期为止

显然,在 Way-2 中,REST API 将需要一种方法来识别和信任令牌为有效令牌。登录 API 执行了验证验证,因此目录中的其他 REST API 需要信任 “代客密钥”。

当然,这意味着需要在 REST API 之间存储和共享 auth 密钥 / 令牌。这个共享的,受信任的令牌存储库可以是本地 / 联合的,从而允许其他组织的 REST API 彼此信任。

但是我离题了。

关键是,需要维护和共享 “状态”(关于客户端的身份验证状态),以便所有 REST API 都可以创建信任圈。如果我们不这样做,那就是方法 1,我们必须接受必须对进入的任何 / 所有请求执行身份验证操作。

执行身份验证是一个资源密集型过程。想象一下,针对您的用户存储针对每个传入请求执行 SQL 查询,以检查 uid / pwd 匹配。或者,加密并执行哈希匹配(AWS 样式)。从结构上讲,我怀疑每个 REST API 都需要使用通用的后端登录服务来执行此操作。因为,如果不这样做,那么您到处都会乱扔身份验证代码。一团糟。

因此,更多的层,更多的延迟。

现在,采用 Way-1 并申请 HTM。您的(人类)用户是否真的在乎您是否必须在每个请求中发送 uid / pwd / hash 或其他内容?不,只要您不每秒扔一次 auth / login 页面就可以打扰她。祝您有个好运。因此,您要做的就是将登录信息存储在客户端的某个位置,即一开始就在浏览器中,然后将其与每个请求一起发送。对于(人类)用户,她已经登录,并且可以使用 “会话”。但实际上,她会根据每个请求进行身份验证。

与 Way-2 相同。您的(人类)用户将永远不会注意到。因此没有造成伤害。

如果我们将 Way-1 应用于 MTM 怎么办?在这种情况下,由于它是一台机器,我们可以通过要求它在每个请求中提交身份验证信息来烦死这个家伙。没人在乎!在 MTM 上执行 Way 2 不会引起任何特殊反应;它是该死的机器。它可能不在乎!

所以说真的,问题是什么适合您的需求。无国籍需要付出代价。付出代价,继续前进。如果您想成为一个纯粹主义者,那就也为此付出代价,然后继续前进。

最后,哲学并不重要。真正重要的是信息发现,表示和消费体验。如果人们喜欢您的 API,那么您就完成了自己的工作。