GET /spec.html HTTP/1.1
Host: www.example.org
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
这是一种易于实现、在所有浏览器上默认可用的方法,但也有一些已知的缺点,比如浏览器显示的糟糕认证窗口(没有类似LogOut的功能),服务器端额外的CPU消耗,以及用户名和密码通过HTTPS传输到服务器(让密码只在客户端保留,输入时存储为安全哈希值更加安全)。
我们可以使用摘要认证,但它同样需要HTTPS,因为它容易受到中间人或重放攻击的攻击,并且仅适用于HTTP。
通过Cookies进行会话
老实说,由服务器管理的会话并不是真正无状态的。
一种可能的解决方案是将所有数据都保存在cookie内容中。而且,按设计,cookie是在服务器端处理的(事实上,客户端甚至不尝试解释此cookie数据:它只是在每个连续请求中将其返回给服务器)。但是这个cookie数据是应用程序状态数据,所以在一个真正的无状态世界中,客户端应该管理它,而不是服务器。
GET /spec.html HTTP/1.1
Host: www.example.org
Cookie: theme=light; sessionToken=abc123
Cookie技术本身与HTTP相关,因此不符合真正的RESTful标准,RESTful应该是独立于协议的,我个人认为。它容易受到MiM或Replay攻击。
通过令牌(OAuth2)授权
另一种方法是将令牌放入HTTP头中以进行请求认证。例如,OAuth 2.0就是这样做的。请参阅RFC 6749:
GET /resource/1 HTTP/1.1
Host: example.com
Authorization: Bearer mF_9.B5f-4.1JqM
所有REST查询必须通过对小写字母按字母顺序进行排序的查询参数进行身份验证,使用私有凭据作为签名令牌。签名应在URL编码查询字符串之前发生。
这种技术可能更适用于无状态架构,并且还可以使用轻量级会话管理(使用内存会话而不是DB持久性)来实现。GET /object?apiKey=Qwerty2010
GET /object?timestamp=1261496500&apiKey=Qwerty2010&signature=abcdef0123456789
被签名的字符串是 /object?apikey=Qwerty2010×tamp=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令牌身份验证可能在"Granted by Token"当前方案方面有很大改进。但这仍然是正在进行的工作,并且与HTTP传输相关。
结论
值得指出的是,REST不仅基于HTTP,虽然在实践中,它主要通过HTTP实现。REST可以使用其他通信层。因此,RESTful身份验证并不仅仅是HTTP身份验证的同义词,无论Google如何回答。它甚至不应使用HTTP机制,而应该从通信层抽象出来。如果使用HTTP通信,由于Let's Encrypt计划的存在,没有理由不使用适当的HTTPS,这是任何身份验证方案所必需的补充。我怀疑那些热情呼喊“HTTP身份验证”的人是否曾尝试过使用REST(而不是机器对机器的Web服务)创建基于浏览器的应用程序(无意冒犯 - 我只是认为他们从未面临过这些复杂问题)。
在生成要在浏览器中查看的HTML页面的RESTful服务上使用HTTP身份验证时,我发现以下问题:
一篇非常有见地的文章逐一解决了这些问题:这里,但这导致了很多特定于浏览器的JavaScript hackery,解决方法的解决方法等等。因此,它也不是向前兼容的,因此需要随着新的浏览器发布进行不断的维护。我认为这不是一个清晰明了的设计方案,而且我认为这是额外的工作和头痛,只是为了让我可以自豪地向我的朋友展示我的REST徽章。
我相信Cookies是解决方案。但是等等,Cookie是邪恶的,不是吗? 不,它们不是,Cookie经常使用的方式是邪恶的。 Cookie本身只是客户端信息,就像浏览器会跟踪您在浏览过程中的HTTP身份验证信息一样。 并且,此客户端状态片段在每个请求中都会发送到服务器,就像HTTP身份验证信息一样。 从概念上讲,唯一的区别在于此客户端状态片段的内容可以由服务器作为其响应的一部分确定。
通过制定以下规则,将会话作为RESTful资源:
唯一不同于HTTP认证的地方是,认证密钥是由服务器生成并发送给客户端保持发送回来的,而不是客户端从输入的凭据计算出来。
converter42 补充说,在使用https时(我们应该这样做),重要的是设置cookie的secure标志,以便身份验证信息永远不会通过非安全连接发送。这是一个很好的观点,我自己还没有看到过。
我认为这是一个足够的解决方案,可以正常工作,但我必须承认,我不是足够的安全专家,无法确定此方案可能存在的潜在隐患 - 我所知道的是,成百上千个非RESTful Web应用程序基本上使用相同的登录协议(PHP中的 $_SESSION,Java EE 中的 HttpSession等)。cookie 头部内容只是用来访问服务器端资源,就像 accept-language 可以用来访问翻译资源一样。我认为这是一样的,但也许其他人不这么认为?你们觉得呢?
已经有很多人在这个话题上说了足够多的话了。但是这是我的看法。
有两种交互模式:
机器是公共因素,表示为REST API,参与者/客户端可以是人或机器。
现在,在真正的RESTful架构中,无状态性的概念意味着所有相关的应用程序状态(即客户端侧状态)必须随每个请求一起提供。有关"相关"的含义是指REST API处理请求并提供适当响应所需的任何内容。
当我们在人与机器的应用程序环境中考虑这一点时,“基于浏览器的”就像Skrebbel上面指出的那样,这意味着运行在浏览器中的(网络)应用程序将需要在每个请求发送其状态和相关信息到后端REST API。
考虑这种情况:您拥有一个暴露为REST API的数据/信息平台资源。也许您有一个自助式BI平台,可以处理所有数据立方体。但是你希望你的(人类)客户通过(1)网络应用程序、(2)移动应用程序和(3)某些第三方应用程序访问这个平台。最终,即使是一系列的MTMs也会导致HTM-对吗。所以人类用户仍然是信息链的顶点。
在前两种情况下,您有一个人机互动的案例,信息实际上由人类用户使用。在最后一种情况下,您有一个机器程序使用REST API。
认证的概念适用于所有情况。您将如何设计这样一种方式,使得您的REST API以统一、安全的方式被访问?在我看来,有两种方法:
方法一:
方式-2:
显然,在Way-2中,REST API需要一种方法来识别和信任有效的令牌。登录API执行了auth验证,因此其他REST API在目录中需要信任那个“valet key”。
当然,这意味着需要存储和共享auth key/token。这个共享的可信令牌存储库可以是本地/联合的,允许来自其他组织的REST API互相信任。
但我偏离主题了。
关键是,需要维护和共享“状态”(有关客户端身份验证状态的信息),以便所有REST API可以创建信任环。如果我们不这样做,即为Way-1,则必须接受必须对所有请求执行身份验证的事实。
执行身份验证是一个资源密集型的过程。想象一下针对您的用户存储库检查uid/pwd匹配的每个传入请求执行SQL查询。或者使用加密和哈希匹配(AWS样式)。并且在架构上,我怀疑每个REST API都需要使用通用后端登录服务来执行此操作。因为如果不这样做,那么您会到处散布auth代码。一团糟。
所以,层数越多,延迟越大。
现在,采用方式1并应用于HTM。对于你的(人类)用户来说,是否必须在每个请求中发送uid/pwd/hash或其他信息并不重要,只要你不会每秒钟都跳出授权/登录页面打扰她。如果你这样做,祝你好运,因为你将失去客户。因此,你需要在开始时将登录信息存储在浏览器中的客户端,并随每个请求一起发送。对于(人类)用户来说,她已经登录,并且“会话”可用。但实际上,在每个请求上进行身份验证。这是一个完全符合RESTful标准的身份验证解决方案:
当客户端进行身份验证时:
3.1. 发布一个包含以下内容的令牌:
3.2. 用私钥加密令牌。
3.3. 将加密的令牌发送回用户。
当用户访问任何API时,他们还必须传递他们的认证令牌。
这是无状态/RESTful身份验证。
请注意,如果包括密码哈希,则用户还将随身份验证令牌一起发送未加密的密码。 服务器可以通过比较哈希值来验证密码是否与用于创建身份验证令牌的密码匹配。需要使用安全连接,如HTTPS。客户端JavaScript可以处理获取用户的密码,并在客户端中存储它,例如在内存或Cookie中,可能使用服务器的公钥加密。
首先,RESTful web服务是无状态的(或者说是无会话的)。因此,RESTful服务不应该有和不应该使用会话或cookie的概念。在RESTful服务中进行身份验证或授权的方式是使用RFC 2616 HTTP规范中定义的HTTP授权头。每个请求都应该包含HTTP授权头,并且请求应该通过HTTPs(SSL)连接发送。这是在HTTP RESTful web服务中进行身份验证和验证请求授权的正确方式。我已经为思科系统的Cisco PRIME性能管理应用程序实现了一个RESTful web服务,并作为该Web服务的一部分,我还实现了身份验证/授权。
这当然不是关于"会话密钥"的问题,而通常用于指代在REST的所有约束条件下执行的无状态认证。每个请求都是自描述的,携带足够的信息以便单独授权该请求,无需任何服务器端应用程序状态。
最简单的方法是从HTTP内置的身份验证机制开始,该机制在RFC 2617中定义。
之前提到的方法实质上是OAuth2.0的“资源所有者密码凭证”授权类型。这是一个轻松上手的方式。然而,采用这种方法,组织中的每个应用程序都将拥有自己的身份验证和授权机制。推荐的方法是“授权码”授权类型。此外,在我之前下面的回答中,我推荐使用浏览器localStorage来存储认证令牌。然而,我现在认为cookie是这个目的的正确选项。我在this StackOverflow answer中详细说明了我的原因、授权码授权类型实现方法、安全考虑等。
采用这种方法,我们每30分钟就会对缓存进行昂贵的操作,以加载用户特定的访问权限详细信息。因此,如果撤销了某个访问权限或授予了新的访问权限,则需要等待30分钟才能反映出来,或者先注销再登录。
我认为RESTful身份验证涉及将身份验证令牌作为请求的参数传递。例如,API使用API密钥。我不相信使用Cookie或HTTP身份验证符合要求。