REST API 登录模式
Posted
技术标签:
【中文标题】REST API 登录模式【英文标题】:REST API Login Pattern 【发布时间】:2012-12-04 16:39:30 【问题描述】:我正在创建一个 REST api,紧跟 apigee 的建议,使用名词而不是动词,在 url 中烘焙的 api 版本,每个集合两个 api 路径,GET POST PUT DELETE 用法等。
我正在开发登录系统,但不确定登录用户的正确 REST 方式。我目前不在安全方面工作,只是登录模式或流程。 (稍后我们将添加 2 步 oAuth,使用 HMAC 等)
可能的选择
类似https://api...com/v1/login.json
的帖子
类似https://api...com/v1/users.json
的PUT
我没有想到的东西......
登录用户的正确 REST 样式是什么?
【问题讨论】:
那是响应格式。 .json 告诉服务器以 json 格式响应,.xml 告诉服务器以 xml 格式响应。而是使它成为 ? 后面的可选参数。 blog.apigee.com/detail/… 从未见过在 URL 上进行的内容协商,仅在标头中。在 URL 上,这意味着您失去了缓存等好处。 @ScottRoepnack 那么你应该考虑Accept
HTTP 标头。
@Oded 如果您使用了Accept
标头,您还将拥有Vary: Accept
,因此缓存不会受到影响。扩展中的连接是discussed before;不过,我同意 Shonzilla 的回答。
@Oded - 我不明白。如果在 URL 中指定内容类型(作为查询路径的 .json 后缀或作为 type=json 查询参数),为什么会失去缓存的好处?在这种情况下,“你”是谁?谁是失去缓存优势的人?在我看来,无论查询路径或参数中的内容是什么,任何查询的结果都可以被缓存。
【参考方案1】:
Principled Design of the Modern Web Architecture by Roy T. Fielding and Richard N. Taylor,即来自所有 REST 术语的工作序列,包含客户端-服务器交互的定义:
所有 REST 交互都是无状态。也就是说,每个请求都包含 连接器了解连接器所需的所有信息 请求,独立于之前的任何请求。
这个限制完成了四个功能,第一个和第三个在这个特殊情况下很重要:
第一个:它消除了连接器保留应用程序状态的任何需要 请求之间,从而减少物理资源的消耗 并提高可扩展性; 3rd:它允许中间人查看和单独理解请求, 当服务动态重新排列时,这可能是必要的;现在让我们回到您的安全案例。每个请求都应包含所有必需的信息,授权/身份验证也不例外。如何做到这一点?从字面上看,每次请求都会通过电线发送所有必需的信息。
如何存档的示例之一是hash-based message authentication code or HMAC。在实践中,这意味着向每个请求添加当前消息的哈希码。 加密散列函数结合秘密密钥计算的散列码。 加密散列函数 是预定义的,或者是 按需代码 REST 概念的一部分(例如 javascript)。 秘密密钥应该由服务器作为资源提供给客户端,客户端使用它来计算每个请求的哈希码。
HMAC实现的例子很多,但我希望你注意以下三个:
Authenticating REST Requests for Amazon Simple Storage Service (Amazon S3) Answer by Mauriceless on quiestion: "How to implement HMAC Authentication in a RESTful WCF API" crypto-js: JavaScript implementations of standard and secure cryptographic algorithms它在实践中的工作原理
如果客户端知道密钥,那么它就可以使用资源进行操作了。否则会被临时重定向(状态码307 Temporary Redirect)授权并获取秘钥,然后重定向回原来的资源。在这种情况下,无需事先知道(即在某处硬编码)授权客户端的 URL 是什么,并且可以随时间调整此架构。
希望这能帮助您找到合适的解决方案!
【讨论】:
MAC 用于证明消息的真实性并防止被篡改 - 它与用户身份验证无关 添加了一个示例,如何在事先不知道“登录 URL”的情况下处理用户/客户端身份验证 这是另外两篇不错的文章,其中包含 REST 服务的无状态身份验证示例:blog.jdriven.com/2014/10/…technicalrex.com/2015/02/20/…【参考方案2】:TL;DR 每个请求的登录不是实现 API 安全性的必需组件,身份验证是。
如果不谈论一般的安全性,很难回答您有关登录的问题。使用一些身份验证方案,没有传统的登录方式。
REST 没有规定任何安全规则,但实践中最常见的实现是具有 3 向身份验证的 OAuth(正如您在问题中提到的那样)。本身没有登录,至少每个 API 请求都没有。使用 3-way auth,您只需使用令牌。
-
用户批准 API 客户端并授予以长期令牌形式发出请求的权限
Api 客户端通过使用长寿命令牌获取短寿命令牌。
Api 客户端随每个请求发送短期令牌。
此方案为用户提供了随时撤销访问权限的选项。我见过的几乎所有公开可用的 RESTful API 都使用 OAuth 来实现这一点。
我只是认为您不应该从登录的角度来描述您的问题(和疑问),而应该考虑总体上保护 API。
有关 REST API 身份验证的更多信息,您可以查看以下资源:
http://www.infoq.com/news/2010/01/rest-api-authentication-schemes REST API Authentication RESTful API Authentication【讨论】:
是的,OAuth!非常直接的答案,应该是公认的答案,恕我直言。【参考方案3】:REST 哲学的一个重要部分是在设计 API 时尽可能多地利用 HTTP 协议的标准特性。将该理念应用于身份验证,客户端和服务器将利用 API 中的标准 HTTP 身份验证功能。
登录屏幕非常适合人类用户用例:访问登录屏幕、提供用户/密码、设置 cookie、客户端在以后的所有请求中提供该 cookie。不能期望使用 Web 浏览器的人为每个单独的 HTTP 请求提供用户 ID 和密码。
但对于 REST API,登录屏幕和会话 cookie 并不是绝对必要的,因为每个请求都可以包含凭据而不会影响人类用户;如果客户端在任何时候都不配合,可以给出401
“unauthorized”响应。 RFC 2617 描述了 HTTP 中的身份验证支持。
TLS (HTTPS) 也是一种选择,它允许在每个请求中通过验证另一方的公钥对客户端进行身份验证(反之亦然)。此外,这确保了获得奖金的渠道。当然,为此需要在通信之前进行密钥对交换。 (注意,这专门用于使用 TLS 识别/验证用户。使用 TLS / Diffie-Hellman 保护通道始终是一个好主意,即使您不通过其公钥识别用户。)
例如:假设 OAuth 令牌是您的完整登录凭据。一旦客户端获得了 OAuth 令牌,它就可以作为标准 HTTP 身份验证中的用户 ID 提供给每个请求。服务器可以在第一次使用时验证令牌,并缓存检查结果以及随每个请求更新的生存时间。如果未提供任何需要身份验证的请求,则返回 401
。
【讨论】:
“因为每个请求都可以包含凭据而不会影响人类用户” 发明了三向身份验证和 OAuth,因为引号中的内容很糟糕。如果您为每个请求提供凭据,而服务器上没有撤销它们的机制,那么如果不使用 SSL,那将是不安全的。 只要有用户的概念,就必须从客户端向服务器传递一些东西来识别哪个用户。 OAuth 令牌当然可以用作此处的“凭据”,而不是实际的用户/密码组合。使用 TLS 保护通道当然总是一件好事,但这几乎是无关紧要的。即使你使用 cookie,某种令牌仍然会随每个请求发送到服务器,只是使用 cookie 标头而不是身份验证标头。 如果您出于某种原因不使用 TLS 或 OAuth,那么每次发送用户/密码真的比只发送一次更糟糕吗?如果攻击者可以获得用户/密码,那么攻击者很可能也可以获得会话cookie。 cookie 和作为凭据的身份验证标头之间的区别在于,cookie 始终与特定域相关联。这意味着当 API 接收到一个 cookie 时,它知道它来自哪里(之前是由同一个域编写的)。使用标头,您永远不知道,您必须为此实施特定检查。一般来说,我同意,它们都是凭据,但我认为传递凭据不是登录。登录是开门的主动动作。在 3-way auth 的情况下,只有客户端的第一次批准才会登录。以上是关于REST API 登录模式的主要内容,如果未能解决你的问题,请参考以下文章
多租户模式:使用 django rest 框架的动态 api 路由