RESTful认证意味着什么?它是如何工作的?我在谷歌上找不到一个好的概述。我唯一的理解是您在URL中传递了会话密钥(rememberal),但这可能是非常错误的。
- 当我谷歌RESTful认证时,我发现了十几个ror插件。我假设这些不是你要找的。如果不是RoR,那是什么语言?什么网络服务器?
- 如果你使用https,那就不会有太大的错误。完整的HTTP请求和URL将被加密。
- @是的,会的。我永远不会在用户可见的URL中传递敏感信息。出于实际目的,这些信息更容易泄露。HTTPS不能帮助防止意外泄漏。
- @jcoffland:真正的RESTful身份验证是什么意思?我很感兴趣,因为我刚刚实现了接受答案的第三种方法,但是我对它不满意(我不喜欢URL中的附加参数)。
- 有些人用jwt.io/introduction来解决这个问题。我现在就做一些研究来解决我的问题:stackoverflow.com/questions/36974163/…>>希望这一切都会好起来。
如何在RESTful客户机-服务器体系结构中处理身份验证是一个有争议的问题。好的。
通常,它可以通过以下方式在SOA over HTTP世界中实现:好的。
- 基于HTTPS的HTTP基本身份验证;
- cookie和会话管理;
- HTTP头中的令牌(例如OAuth 2.0+JWT);
- 使用其他签名参数查询身份验证。
您将不得不调整,甚至更好地混合这些技术,以最好地匹配您的软件架构。好的。
根据安全策略和软件体系结构的目的,每个身份验证方案都有其各自的优缺点。好的。
基于HTTPS的HTTP基本身份验证好的。
第一个解决方案基于标准的HTTPS协议,被大多数Web服务使用。好的。
1 2 3
| GET /spec.html HTTP/1.1
Host: www.example.org
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== |
它很容易实现,默认情况下在所有浏览器上都可用,但是有一些已知的缺点,例如浏览器上显示的糟糕的身份验证窗口,它将持续存在(这里没有类似于注销的功能),一些服务器端额外的CPU消耗,以及用户名和密码(通过https)传输到服务器的事实。(在键盘输入期间,只让密码留在客户机端,并在服务器上作为安全散列存储,这应该更安全)。好的。
我们可以使用摘要式身份验证,但它也需要HTTPS,因为它容易受到MIM或重播攻击,并且是特定于HTTP的。好的。
通过cookie会话好的。
老实说,在服务器上管理的会话并不是真正的无状态会话。好的。
一种可能是维护cookie内容中的所有数据。而且,根据设计,cookie是在服务器端处理的(事实上,客户机甚至不尝试解释这个cookie数据:它只是在每次连续请求时将其交回服务器)。但是这个cookie数据是应用程序状态数据,所以客户机应该在一个纯无状态的世界中管理它,而不是管理服务器。好的。
1 2 3
| GET /spec.html HTTP/1.1
Host: www.example.org
Cookie: theme=light; sessionToken=abc123 |
号
cookie技术本身是HTTP链接的,所以它不是真正的RESTful,它应该是独立于协议的,imho。它易受MIM或重放攻击。好的。
通过令牌授予(OAuth2)好的。
另一种方法是在HTTP头中放置一个令牌,以便对请求进行身份验证。例如,这就是OAuth2.0所做的。参见RFC 6749:好的。
1 2 3
| GET /resource/1 HTTP/1.1
Host: example.com
Authorization: Bearer mF_9.B5f-4.1JqM |
简言之,这与cookie非常相似,并面临着同样的问题:非无状态,依赖于HTTP传输细节,并且受到许多安全弱点(包括mim和replay)的影响,因此只能在https上使用。通常,JWT用作令牌。好的。
查询身份验证好的。
查询身份验证包括通过URI上的一些附加参数对每个RESTful请求进行签名。请参阅本参考文章。好的。
本条将其定义为:好的。
All REST queries must be authenticated by signing the query parameters
sorted in lower-case, alphabetical order using the private credential
as the signing token. Signing should occur before URL encoding the
query string.
Ok.
号
这种技术可能更兼容无状态体系结构,并且也可以通过轻型会话管理(使用内存会话而不是DB持久性)来实现。好的。
例如,下面是来自上面链接的通用URI示例:好的。
1
| GET /object?apiKey=Qwerty2010 |
应按如下方式传送:好的。
1
| 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日志被破坏,您肯定会遇到更大的安全问题。好的。
在实践中,OAuth2.0即将到来的MAC令牌认证可能是对"令牌授权"当前方案的巨大改进。但这仍然是一项正在进行的工作,并且与HTTP传输紧密相连。好的。
结论好的。
值得总结的是,REST不仅是基于HTTP的,即使在实践中,它也主要是通过HTTP实现的。休息可以使用其他通信层。因此,不管谷歌如何回答,RESTful认证不仅仅是HTTP认证的同义词。它甚至不应该使用HTTP机制,而是应该从通信层抽象出来。如果您使用HTTP通信,由于let's encrypt计划,没有理由不使用适当的HTTPS,这是除任何身份验证方案之外所必需的。好的。好啊。
- 如果您使用Cookie作为HTTP Basic Auth的更好替代,那么您可以使用一种使身份验证过期的方法和注销的能力进行真正的无状态身份验证。示例实现可以使用名为Emulated-HTTP-Basic-Auth的cookie,该cookie的值与实际HTTP基本身份验证的值类似,另外还设置了过期时间。然后可以通过删除该cookie来实现注销。我想任何能够支持HTTP基本身份验证的客户机也可以通过这种方式支持cookie身份验证。
- @但正如我所写,这个cookie仍将由服务器管理。它是某种无状态的,但不是"纯"无状态的。在所有情况下,您都需要专门用于客户机登录/注销的JavaScript代码,这是完全可能的,例如,使用HTTP Digest auth-好主意,但在这里没有大的好处,来重新发明轮子。
- 我声称服务器实现了用于配置头的UI和逻辑,但头本身是无状态的。为API设计的客户机可以使用服务器帮助来配置头文件,并只传递类似于HTTP基本身份验证的所需信息。我的观点是,通用UAS(浏览器)的基本身份验证实现太差,无法使用。可以使用服务器为另一个头段(Cookie中的相同内容提供的仿真。
- 当然,服务器可以支持同时接受HTTP基本身份验证和cookie。但是,尽量不要从浏览器请求HTTP基本身份验证,以避免出现错误的UI。
- 我想正确答案是stackoverflow.com/questions/6068113/…
- @事实上,这正是我的答案所建议的:即使会话可能不是100%状态化的,它们也非常方便,可以/应该毫无畏惧地使用。我的观点是,RESTful过程不应该绑定到HTTP特定的模式,比如cookie或HTTP身份验证。在我们的mormot.net框架中,我们对REST身份验证实现了一个简单但功能强大的会话管理,而不绑定到HTTP。见我答案的最后一段。
- 在查询认证时:(从您提供的链接,credits@ron wail)"我不同意URL中的认证信息,因为它的位置不对。URL名称资源、HTTP头是认证、内容协商等应该在的地方。仅仅因为人们误解了REST是一种风格,并且坚持通过URL强制使用类似RPC的方法,并不意味着我们应该适应它。"+您会丢失缓存和代理。我不能更赞同这个人。
- 这些解决方案都不是真正的宁静。每一个都需要在服务器上保留一些特定于客户机的状态。为什么对休息有如此广泛的误解?
- @jcoffland你是对的:"纯"的RESTful不是友好的认证,由设计。一个cookie可以在没有任何服务器端状态的情况下实现,就像查询认证一样。但它可能会使它比一些"轻"的服务器端会话更不安全和方便。完全无国籍(一种宁静主义?)不是所有用例的解决方案imho。
- 用"消化"代替"基本"怎么样?
- @njzk2不会改变问题:弹出奇怪的对话框输入用户/密码凭据,然后向服务器发出不安全的请求(摘要对mim和重放攻击很敏感)。因为密码在传输过程中是散列的,所以它比basic稍好一点。这就是为什么basic在这里仍然被大量使用的原因,因为它更容易实现,并且所有的安全性都留在了https级别。双向挑战和URI签名更安全。
- 只有服务器通过发送401未经授权的响应来请求HTTP授权时,才会出现丑陋的密码提示。如果你不喜欢它,只需发送403禁止代替。错误页面可能包含登录方法或指向该方法的链接。但是,反对cookie和HTTP身份验证(不管状态是服务器端还是客户机端)的最大理由是它们容易受到跨站点请求伪造的攻击。因此,最佳方法是自定义授权方案、自定义授权头或自定义get或post参数。
- 我想知道,为什么您假设API请求是通过浏览器发送的?它们很可能是通过curl或某种编程语言的客户机发送的。
- @Alexandersupertramp我不做这个假设,我只是相反地说,其余的不应该绑定到HTTP(比如使用cookie)。事实上,这就是这个答案的要点。有了我们内部的开源框架,您可以使用REST模式和JSON创建Ajax/Browser应用程序、Windows客户端,甚至是独立的应用程序——事实上,这是一个很好的设计选择,例如为了安全或进化。:)如果从浏览器运行,基本身份验证将弹出一个糟糕的对话框,输入名称和密码。
- @阿尔文我删除了你的stackoverflow.com/revisions/7158864/9,因为编辑答案不是如何发表评论。我在我的答案中添加了一个小注释,说明在URI中签名可能引起的问题。
- @Arnaudbouchez我明白了——这不是解决这个问题的正确方法——但是我认为你的评论没有正确地指出这个漏洞的重要性——这是多年前的一种解决方法,但是添加了一个完整的HTTP头来解决这个问题,并且应该在每次可能的时候用它来代替这种方法——加密连接不值得使用mu。ch如果您的凭证没有用它们加密--这是一个可接受的答案,请更新或添加关于建议使用Authorized头vs uri编码的更详细说明。
我怀疑那些狂热地叫喊"HTTP认证"的人是否曾经尝试过用REST来制作基于浏览器的应用程序(而不是机器到机器的Web服务)(无意冒犯——我只是认为他们从未遇到过复杂的情况)。
我在生成要在浏览器中查看的HTML页面的RESTful服务上使用HTTP身份验证时发现的问题是:
- 用户通常会得到一个丑陋的浏览器制作的登录框,这是非常不友好的用户。不能添加密码检索、帮助框等。
- 注销或以其他名称登录是一个问题-浏览器将继续向站点发送身份验证信息,直到关闭窗口。
- 超时很困难
这里有一篇非常有见地的文章,可以逐点解决这些问题,但是这会导致许多浏览器特定的javascript黑客,解决方法的解决方法,等等。因此,它也不能向前兼容,因此在发布新浏览器时需要不断地维护。我不认为这是一个干净清晰的设计,而且我觉得这是一个额外的工作和头痛,只是为了让我能热情地向我的朋友展示我的休息徽章。
我相信曲奇是解决办法。等等,饼干是邪恶的,不是吗?不,他们不是,饼干的使用方式是邪恶的。cookie本身只是客户端信息的一部分,就像浏览器在浏览时跟踪的HTTP身份验证信息一样。而这段客户端信息在每次请求时都会发送到服务器,就像HTTP身份验证信息一样。从概念上讲,唯一的区别是,作为响应的一部分,服务器可以确定这段客户端状态的内容。
通过使用以下规则使会话成为一个可休息的资源:
- 会话将密钥映射到用户ID(也可能是超时的最后一个操作时间戳)
- 如果会话存在,则表示密钥有效。
- 登录意味着发布到/会话,新密钥被设置为cookie
- 注销意味着删除/sessions/键(在超负荷的帖子中,记住,我们是一个浏览器,HTML 5还有很长的路要走)
- 通过在每次请求时将密钥作为cookie发送并检查会话是否存在以及是否有效,可以完成身份验证。
现在,与HTTP身份验证唯一不同的是,身份验证密钥是由服务器生成的,并发送给不断发送它的客户机,而不是由客户机根据输入的凭据计算它。
Converter42补充说,在使用HTTPS(我们应该这样做)时,重要的是cookie将设置其安全标志,这样就不会通过非安全连接发送身份验证信息。很好,我自己没见过。
我认为这是一个很好的解决方案,但我必须承认,我还不够安全专家来识别这个方案中的潜在漏洞——我所知道的是,数百个非REST的Web应用程序基本上使用相同的登录协议(PHP中的$Sub会话、JavaEE中的HTTP会话等)。cookie头内容仅用于处理服务器端资源,就像接受语言可能用于访问翻译资源等。我觉得是一样的,但也许其他人不一样?你们觉得怎么样,伙计们?
- 这是一个务实的答案,建议的解决方案是有效的。但是,在同一句话中使用术语"restful"和"session"是错误的(除非在两者之间还有"not")。换句话说:任何使用会话的Web服务都是不可恢复的(根据定义)。别误会我——你仍然可以使用这个解决方案(ymmv),但是术语"restful"不能用于它。我推荐奥雷利的《休息》一书,这本书可读性很强,对这个主题有深入的解释。
- @约翰多多,可能是,但你打算如何做认证?或者至少要承认,制作一个网络应用是不可能的(应用,而不是服务!)这是休息的(根据你的严格定义)。但是你所引发的宗教书呆子战争没有实际用途。
- @skrebbel:pure-rest解决方案每次请求一个不太完美的资源时都会发送身份验证数据(http-auth这样做)。建议的解决方案对大多数用例都是有效的,而且更适合使用,但是它不是一个静止的解决方案。不需要战争,我也用这个办法。我只是不认为这是休息。:)
- 会话只是RESTful身份验证的一种方式-有几种方法可用。正如约翰多多所说,它不是纯粹的RESTful:这只是通过HTTP实现它的常见方法。
- 哦,来吧,举个例子。另一种方法是什么?效果很好?我真的很想知道。HTTP认证当然不是,如果不关闭浏览器,您就无法注销,如果没有大量特定于浏览器的不兼容JS,您就无法提供像样的登录UX。我不太关心"纯粹的休息"和"几乎休息"以及整个相关的宗教辩论,但是如果你说有几种方法,你应该把它们拼出来。
- 使用真实世界的用户代理(也称为"浏览器")进行真正的RESTful身份验证由一个包含HTTP身份验证值的cookie组成。这样,服务器可以提供用于输入登录名和密码的UI,并且服务器可以强制注销(通过删除cookie)。此外,当身份验证失败时,服务器必须使用临时重定向到登录屏幕,而不是响应401以要求登录,而在成功登录后,使用临时重定向返回到以前的位置。另外,服务器必须将注销操作(post-form)嵌入到登录用户的几乎每个页面中。
- 我不明白为什么这个答案比@arnaudbouchez的答案更有投票权。他描述了查询认证的第三种方法,正如他所说,这可能是最接近"无状态"原则的方法。
- @哈拉兰-这只是一个更古老的答案,所以它有更多的时间来收集选票。也就是说,我不确定查询身份验证选项如何很好地映射到Web应用程序。注意,我们讨论的是浏览器在这里查看页面,而不是编程的REST客户机与REST服务器通信。我还没有完全解决这个问题,但我也不确定我是否希望身份验证令牌出现在我的浏览器历史记录中。
- 我不认为在同一句话中使用"restful"和"session"有任何错误,只要清楚会话只存在于客户端。我不知道为什么这个概念会有这么大的影响。
- 我花了几天时间阅读关于RESTful AUTH的各种主题。我得出了一个类似的结论,即对于最严格的要求,100%的"休息"是不可能的,并且让浏览器访问一个安全的API(无论如何都没有OpenID)。你可以让一个Web应用代理代表用户访问API,但是你必须添加更多的代码,这是为了理想而模糊的,在这种情况下不适用。即使在下面的查询签名中,也需要有一个共享的秘密。与在cookie imo中存储秘密相比,拥有一个会话更好,您还如何存储数据客户端?
- HTTP基本认证也可以通过javascript来完成,对吗?所以你不一定要坚持使用难看的浏览器框。我正在考虑一个单页的应用程序,考虑到这个答案是从'09年开始的,这可能是不公平的,但是您可以做基本的认证,将凭证存储在客户端上,并将它们发送到您通过javascript执行的每个后续请求的头中。
- 如果使用cookies,这是否意味着您的客户机必须启用cookies?如果是这样,服务器定义所需的auth头是否更可靠?我自己做的很好。当然,REST服务不会指定客户机如何存储作为凭证提供的头值-客户机甚至可以使用cookie:)。
- 如果你使用cookies,那么你就打开了跨站点请求伪造的可能性。我想亚马逊已经在这里获得了认证。他们的计划是复杂的,但安全和"休息"。
- 嗯,很有洞察力。有关于这个的资料吗?或者你是通过阅读amazon.com的资料发现它的?
- @我想他指的是这个
在这个问题上,这里的好人已经说得够多了。但这是我的2美分。好的。
有两种交互模式:好的。
人机对话(HTM)
机器对机器(MTM)
机器是通用的分母,用RESTAPI表示,而参与者/客户机既可以是人,也可以是机器。好的。
现在,在一个真正的RESTful体系结构中,无状态的概念意味着所有相关的应用程序状态(即客户端状态)必须随每个请求一起提供。相关的意思是,RESTAPI需要什么来处理请求并提供适当的响应。好的。
当我们在人机交互应用程序的上下文中考虑到这一点时,正如skrebbel上面指出的那样,"基于浏览器",这意味着在浏览器中运行的(web)应用程序需要将其状态和相关信息连同它发出的每个请求一起发送到后端REST API。好的。
考虑一下:您有一个数据/信息平台公开了RESTAPI的资产。也许您有一个自助式BI平台来处理所有的数据多维数据集。但您希望您的(人类)客户通过(1)Web应用程序,(2)移动应用程序和(3)某些第三方应用程序访问此应用程序。最后,甚至连一系列的MTM都会指向HTM-右。因此,人类用户仍然处于信息链的顶端。好的。
在前2个案例中,您有一个人机交互的案例,这个信息实际上是由一个人类用户消耗的。在最后一种情况下,您有一个使用其余API的机器程序。好的。
认证的概念适用于整个系统。您将如何设计它,以便以统一、安全的方式访问您的RESTAPI?我认为有两种方法:好的。
路1:好的。
首先,没有登录名。每个请求执行登录
客户端发送其标识参数+特定于请求的每个请求的参数
其余的API接受它们,返回,Ping用户存储(无论是什么)并确认授权
如果建立了身份验证,则为请求提供服务;否则,拒绝使用适当的HTTP状态代码
在您的目录
WAY-2:好的。
客户端以身份验证请求开始
登录RESTAPI将处理所有此类请求
它接受auth参数(api密钥、uid/pwd或任何选择)并根据用户存储(ldap、ad或mysql db等)验证身份验证。
如果已验证,则创建一个身份验证令牌并将其交回客户/呼叫者
然后,调用方发送此身份验证令牌+请求特定参数在注销或租约到期之前,对其他Business Rest API的每个后续请求
显然,在方法2中,其余的API需要一种方法来识别和信任令牌是否有效。登录API执行了身份验证,因此目录中的其他RESTAPI需要信任"代客密钥"。好的。
当然,这意味着需要在其余的API之间存储和共享auth密钥/令牌。这个共享的、受信任的令牌存储库可以是本地/联邦的,允许来自其他组织的RESTAPI相互信任。好的。
但我离题了。好的。
关键是,需要维护和共享一个"状态"(关于客户机的身份验证状态),以便所有RESTAPI都可以创建一个信任圈。如果我们不这样做(这就是方法1),我们必须接受必须对进入的任何/所有请求执行身份验证操作。好的。
执行身份验证是一个资源密集型过程。想象一下,对于每个传入的请求,对您的用户存储执行SQL查询,以检查uid/pwd是否匹配。或者,加密并执行哈希匹配(AWS样式)。在体系结构上,我怀疑每个RESTAPI都需要使用一个公共的后端登录服务来执行这一操作。因为,如果你不这样做,那么你就会到处乱丢认证代码。一团糟。好的。
所以层越多,延迟就越长。好的。
现在,采用方法1并应用于HTM。你的(人类)用户真的关心你是否需要在每个请求中发送uid/pwd/hash或者其他什么?不,只要你不通过每秒抛出auth/login页面来打扰她。如果你有顾客,祝你好运。所以,您要做的是将登录信息存储在客户机端的某个地方、浏览器中,并在开始时将其与所做的每个请求一起发送。对于(人类)用户,她已经登录,并且"会话"可用。但实际上,她每一个请求都是经过认证的。好的。
与2号路相同。您的(人类)用户永远不会注意到。所以没有造成任何伤害。好的。
如果我们把方法1应用到MTM呢?在这种情况下,由于它是一台机器,我们可以通过请求它在每个请求中提交身份验证信息来让这个人厌烦。没人在乎!在MTM上执行way-2不会引起任何特殊反应,它是一台该死的机器。它可能不那么重要!好的。
所以,实际上,问题是什么适合你的需要。无国籍需要付出代价。付出代价,继续前进。如果你想成为一个纯粹主义者,那么也要为此付出代价,然后继续前进。好的。
最后,哲学并不重要。真正重要的是信息发现、展示和消费体验。如果人们喜欢你的API,你就做了你的工作。好的。好啊。
- 先生,您解释得很好,我对手头的基本问题有了一个清晰的概念。你就像佛陀!我可以补充一下,通过在传输层使用HTTPS,我们甚至可以防止中间人攻击,这样就不会有人劫持我的标识符密钥(如果选择了way-1)
- 它不总是一台进行身份验证的机器吗?人类不会在密码上胡说八道,这对正确合理化安全性的用户来说是一种不幸的烦恼。对我来说,这是一个开发人员的问题,他们想让机器如何工作。
- 很抱歉,您所描述的仍然不是100%剩余,因为您正在服务器上存储用户凭据。这些凭证是服务器端状态。请参阅我对100%RESTful身份验证解决方案的回答。
- 我阅读了您的答案;在您的解决方案中,对于通过用户单击在浏览器上发起的每个Web请求,都需要将"auth token"发送回用户单击调用的任何API。那么呢?API对令牌执行检查。反对什么?针对某种"令牌存储",维护该令牌是否有效。你不同意"令牌存储"成为"状态"的守护者吗?实际上,不管您如何看待这一点,在某个地方,必须有人知道关于"令牌"在用户活动中传递的一些信息。这就是国家信息的所在地。
- "无状态"服务的真正含义是特定的服务器组件(CRUDAPI)不携带任何状态。他们不能从另一个用户中识别出一个用户并在一个事务中完整地完成用户请求。那就是无国籍。但一定有人坐在某个地方,判断这个用户是否有效。没有其他方法可以做到这一点:密钥或密码或其他。从用户端传递的任何内容都必须经过身份验证和授权。
- 您缺少Way-3,混合方法。客户机以Way-2的方式登录,但与Way-1的方式一样,不会根据任何服务器端状态检查凭证。无论如何,都会创建一个auth令牌,并像Way-2中那样发送回客户机。稍后,使用非对称加密检查此令牌的真实性,并查找任何特定于客户端的状态。
- @jcoffland您所描述的是一个系统,它确定用户在某个点通过了身份验证检查,但没有通过哪个身份验证检查。你不知道他们是谁,更不用说他们可以访问什么,只是他们在某个时候提供了通过认证的证书。您如何确定他们是谁,以及他们是否应该访问当前资源?或者您系统上所有经过身份验证的用户都可以访问所有受保护的资源吗?
这里有一个真正的、完全静止的身份验证解决方案:
在身份验证服务器上创建公钥/私钥对。
将公钥分发到所有服务器。
当客户端进行身份验证时:
3.1。颁发包含以下内容的令牌:
- 有效期
- 用户名(可选)
- 用户IP(可选)
- 密码哈希(可选)
3.2。用私钥加密令牌。
3.3。将加密令牌发送回用户。
当用户访问任何API时,他们还必须传递其身份验证令牌。
服务器可以通过使用身份验证服务器的公钥对令牌进行解密来验证令牌是否有效。
这是无状态/RESTful身份验证。
注意,如果包含密码哈希,用户还将发送未加密的密码和身份验证令牌。服务器可以通过比较哈希来验证密码是否与用于创建身份验证令牌的密码匹配。使用类似https的安全连接是必要的。客户机端的javascript可以处理获取用户密码并将其存储在客户机端,或者存储在内存中,或者存储在cookie中,可能使用服务器的公钥加密。
- 如果有人持有该认证令牌并用它假装为客户机来调用API,会怎么样?
- @阿比迪,是的,这是个问题。您可能需要密码。密码的哈希值可以包含在身份验证令牌中。如果有人能够窃取令牌,它将很容易受到离线暴力攻击。如果选择了一个强密码,那就不会有问题。注意,如果使用HTTPS令牌盗窃,则需要攻击者首先获得对客户端计算机的访问权。
- 如果服务器上同时进行加密和解密,为什么要使用公钥/私钥?
- 因为只有身份验证服务器知道私钥。其他服务器只需知道公钥和用户令牌就可以对用户进行身份验证。
- 这对人类用户不起作用,是吗?
- 这和HMAC有什么不同吗?
- @当然,为什么不呢?用户可以输入密码来解锁存储为cookie或浏览器上本地存储的令牌。
- qpreexo,我想你可以使用hmac方案,但这个想法并不局限于此。
- 非对称加密和解密比对称加密慢一个数量级(计算量更大)。让服务器在每次调用时使用公钥解密令牌将是一个巨大的性能瓶颈。
- @jcoffland您确实在这里推广了您的答案(重复地:—),但我还是忍不住对每次调用都使用非对称加密的性能问题(计算强度)发表评论。我只是看不到一个解决方案,它具有任何扩展能力。查找https和spdy协议。它将尽可能保持连接的开放(http keep alives,即state),并在同一个连接(more state)上批量服务多个资源,当然,SSL本身只使用非对称加密来交换对称的密码密钥(也称state)。
- …因为对称加密比不对称加密快一个数量级。HTTPS最慢、最阻塞管道的方面是初始握手,涉及使用公共/私有密钥加密消息。如果HTTPS没有为所有后续通信切换到共享的秘密对称加密,那么实际的、实际的现实世界性能将是不可接受的,并且解决方案永远无法扩展,至少在没有不可接受的资源成本的情况下是不可接受的。
- @阿比迪您可以向令牌添加一个过期时间和/或将其绑定到IP地址。
- 我现在正在做一个基于令牌的"伪REST"(为了防止人们说,这不是RESTful,因为您在服务器上存储了一个令牌)。顺便说一句,在编码一段时间时,混合了基于RAM和基于HD的DB,以提高对每个令牌的检查速度,在吸烟的时候,我想出了一个同样疯狂的想法:"为什么不简单地打包一个凭证,确认JSON和AES脚本,没有人可以复制ID,我不担心DB查找,我可以在那里存储我想要的任何东西"…嗯,我只是担心我从4000 Java代码转换到这可能是100线解决方案…
- 我完全失去了对代币的控制。如果有人注销怎么办?理论上,令牌仍然有效,没有人执行主要的测试,而不是解密和检查exp-date是否仍然大于now()。如果用户说,决定是否有人伪造了他的凭证,并"更改密码",这意味着什么?在处理令牌时,我不会在任何服务器上回首…会有用吗?是的,会有人偷走那些代币吗?也许,不比偷密码容易,但密码可以更改,我同意用户换一个新的,这样的令牌就像一个路人,不能被破坏。
- 在步骤3中,您会说:"当客户机进行身份验证时"。你是怎么做到的?通过向服务器发送用户ID和密码?或者通过发送公钥?谢谢。
- 这个解决方案有很多问题。严格来说,它可能是"真正的RESTful"认证。关于这个和其他答案的评论中已经概述了许多问题,但似乎有两个核心缺陷:1)效率和2)安全。1)在规模上,执行非对称加密来验证每个请求上发出的令牌是非常有问题的。2)身份验证在发布时及时锁定;用户凭证或访问权限的任何后续更改均不起作用。这是这个安全计划中最糟糕(也是最危险的)的一部分,需要极度小心。
- @Rintaun,不是每个应用程序都需要扩展到这一点。我甚至可以这么说,大多数应用程序都不需要这样的伸缩级别。关于安全性,完全可以授予时间限制的凭证,并要求用户更新过期的令牌以获得对资源的访问权。令牌更新可以自动进行,并对用户隐藏。重新颁发新令牌时,可以添加或删除权限。但是,如果您在某个地方跟踪数据库中的用户权限,那么它就不是真正的RESTful,所以您的第二点是无意义的。
老实说,我在这里看到了很好的答案,但有一点让我感到困扰的是,当有人将整个无状态的概念推向极端时,它就会变得教条化。它让我想起那些只想拥抱纯OO的旧的Smalltalk粉丝,如果某个东西不是一个对象,那么你就做错了。让我休息一下。
休息的方法应该让你的生活更轻松,减少会议的开销和费用,试着遵循它,因为这是一件明智的事情,但一旦你遵循一个纪律(任何纪律/指导方针)到了极端,它不再提供它的目的,那么你就错了。今天一些最好的语言既有函数式编程,也有面向对象的。
如果解决问题的最简单方法是将身份验证密钥存储在cookie中并发送到HTTP头上,那么就这样做,不要滥用它。记住,当会话变得沉重和庞大时,它们是不好的,如果所有会话都由一个包含键的短字符串组成,那么有什么大不了的?
我愿意接受评论中的更正,但我不认为(到目前为止)仅仅是为了避免在服务器上保存一本大的哈希字典而让我们的生活变得悲惨。
- 人们并没有试图禁止你使用会话。你可以自由地去做。但如果你这样做了,那就不是休息。
- @andr&233;caldas它不是以语言中的函数或原语类型不是oop的方式休息的。我不是说开会是明智的。我只是给出了我的意见,关于遵循一系列的实践,在某种程度上,它们不再为某人提供利益。(顺便说一句,注意到我没有反对你的言论,但我不会说这不是休息,我会说这不是纯粹的休息)。
- ---同意!-)
- 如果不安静我们怎么称呼它?当然,如果一个请求包含会话ID,那么它就像一个包含用户ID的请求一样无状态?为什么用户ID是无状态的,会话ID是有状态的?
- "为什么用户ID是无状态的,会话ID是有状态的?"我猜是因为会话是不稳定的数据。在大多数情况下,会话并不代表业务实体,而用户可以被视为与业务相关的持久数据。
- cookie易受跨站点请求伪造的攻击,因此更容易发生安全漏洞。最好使用浏览器不自动发送的内容,如自定义头或自定义授权方案。
- @arg20,用户ID是有状态的。这是很多人犯的错误。他们希望忽略用户ID的状态,因为没有任何真正好的解决方案来解决这个问题,但他们仍然希望称其应用程序为restful。当然,这有点迂腐,但是ops的问题是100%的RESTful认证。
- @jcoffland我只会同意你的声明,如果你的ID随着时间的推移而改变,这在大多数实际情况下是没有意义的。如果你的身份证是不变的,我不知道它需要如何保持状态。
- 事实上,试图做到无状态并不是关于教条主义,而是关于SOA本身的一个共同概念。服务应该总是受益于不耦合和无状态:在实践中,它简化了可伸缩性、可用性和可维护性。当然,它应该尽可能多,并且您最终需要一些"协调服务"来将这些无状态服务管理成有状态的实用方法。
首先,RESTful Web服务是无状态的(或者换句话说,无会话的)。因此,RESTful服务没有也不应该包含会话或cookie的概念。在RESTful服务中进行身份验证或授权的方法是使用RFC2616HTTP规范中定义的HTTP授权头。每个请求都应该包含HTTP授权头,并且请求应该通过HTTPS(SSL)连接发送。这是在HTTP RESTful Web服务中进行身份验证和验证请求授权的正确方法。我已经为Cisco Systems的Cisco Prime Performance Manager应用程序实现了一个RESTful Web服务。作为Web服务的一部分,我也实现了身份验证/授权。
鲁本斯·戈麦斯。
- HTTP身份验证仍然需要服务器跟踪用户ID和密码。这并不是完全无状态的。
- 从某种意义上说,每个请求本身都是有效的,没有以前请求的任何要求,这是无状态的。如何在服务器上实现这一点是另一回事,如果身份验证费用高昂,您可以进行一些缓存,并在缓存未命中时重新进行身份验证。很少有服务器是完全无状态的,其中输出纯粹是输入的函数。它通常是某个状态的查询或更新。
- 不是真的。在这种情况下,您的所有请求都需要上一个事务的状态,即用户注册。我不明白为什么人们总是说存储在服务器上的用户名和密码不是服务器端状态。看看我的答案。
- @jcoffland您的解决方案工作得很好,相当优雅,但是我建议您在休息时回顾一下"状态"的定义好吗?在这方面,我所读到的有关REST的所有内容似乎都指向请求中的某个内容,该请求会引起服务器上状态的显著变化。检索认证信息是如何完成这一任务的?在回答之前,请考虑这样一种情况,即访问不仅需要经过身份验证,还需要经过授权。如何存储用户名或类似于API服务器的内容?
- @另外,您的解决方案严重依赖于API服务器解密签名令牌的能力。我认为这种方法不仅过于具体,而且有点过于复杂,不足以被认为是费尔丁在处理RESTful身份验证问题时所考虑的。
- @Mike我同意这不是目前的方法,但是如果有人要实现它,那么它可能会成为方法。例如,Google可以将其实现为OAuth4.0,其中Google以这种形式向用户发布登录令牌,您的服务器可以通过检查Google的签名和时间戳来验证这些令牌。而且,几乎所有服务器端软件都有能力进行这种加密。它内置于Python、Java、PHP、NoDE.js等。
- SSL不是无状态的。
- @Eddieb你是绝对正确的,ssl是无状态的。
- @jcoffland您是否了解不对称加密有多深入,计算密集(因此资源密集,速度非常慢)?您所说的是一种方案,在每个请求上都使用非对称加密。HTTPS最慢的方面是初始握手,它涉及创建公钥/私钥以不对称地加密共享机密,随后用于对称地加密所有后续通信。
- 对称加密速度如此之快,以至于使用它的开销可以忽略不计,这与不对称加密完全不同。因此,共享的秘密在客户机和服务器上都存储为(gasp)状态。事实上,性能问题非常明显,HTTP keep alives用于保持客户机和服务器之间的连接处于开放状态(更多状态),特别是为了避免每次调用非对称加密函数(查看spdy协议)时花费大量的计算资本。
- 我想我的观点是,纯粹主义并不总是实用的。
- 是的,当然http aka rest是无状态的,所有的auth都在上面。所以,是的,所有的API解决方案都有点偏离纯REST。而且…我们必须在其他地方使用auth。实现身份验证的方式可以是任何适合应用程序的方式。
当然,这与"会话密钥"无关,因为它通常用于指在REST的所有约束内执行的无会话身份验证。每个请求都是自描述的,它携带足够的信息,可以在没有任何服务器端应用程序状态的情况下自行授权请求。
最简单的方法是从RFC2617中的HTTP内置身份验证机制开始。
- HTTP身份验证要求服务器存储用户名和密码。这是服务器端状态,因此不是严格静止。看看我的答案。
- @杰科夫兰:这两个方面都不是真的。第一个HTTP身份验证不需要服务器来存储密码。密码的散列将被存储(建议使用8轮以上的bcrypt)。其次,服务器没有任何状态,因为授权头随每个请求一起发送。如果您将存储的密码散列视为状态,那么它们的状态不会比存储的公钥多。
- @是的,我知道密码是作为散列存储的。哈希密码仍然是特定于客户端的状态。与存储公钥(如我的解决方案中所述)不同的是,只有一个公钥,即身份验证服务器的公钥。这与为每个用户存储密码哈希非常不同。如果服务器为每个用户存储了一个密码,那么无论您如何打扮它,它都是按用户状态存储的,而不是100%休息。
- 我认为在服务器上存储用户哈希密码不应该被视为服务器端状态。用户是资源,包含名称、地址或哈希密码等信息。
@skrebel提到的"非常有洞察力"的文章(http://www.berenddeboer.net/rest/authentication.html)讨论了一种复杂但真正失败的身份验证方法。
您可以尝试访问http://www.berenddeboer.net/rest/site/authenticated.html,而不使用任何登录凭据。
(抱歉,我无法对答案发表评论。)
我会说,REST和身份验证只是不混合。rest表示无状态,但"authenticated"是状态。不能将它们都放在同一层。如果你是一个宁静的倡导者并且不喜欢国家,那么你必须使用HTTPS(即,将安全问题留给另一层)。
- stripe.com会对您关于REST和身份验证的评论说其他的,而不是混合的。
- 无状态仅指服务器,而不是客户机。客户机可以记住会话的所有状态,并发送与每个请求相关的内容。
- 最后,有人说了一些道理,但无状态认证可以使用公钥加密。看看我的答案。
- 服务器没有"已验证"状态。它通过超媒体接收信息,并且必须与之合作以返回请求的内容。再少也没有了。如果资源受到保护,并且需要身份验证和授权,则提供的超媒体必须包含该信息。我不知道在返回资源之前对用户进行身份验证意味着服务器正在跟踪状态的概念来自何处。提供用户名和密码可以被认为是简单地提供更多的过滤参数。
- "我想说的是,REST和身份验证不能混用。"听起来像是常识。除了一个与认证不兼容的系统("认证"本身当然是一种状态)的效用有限。我觉得我们都是在实用主义和纯粹主义教条主义的交叉点上争论,坦率地说,实用主义应该获胜。有很多方面的休息是非常有益的,没有进入扭曲尝试避免状态认证,不是吗?
2019年2月16日更新
下面前面提到的方法实质上是OAuth2.0的"资源所有者密码凭据"授予类型。这是一种简单的起床和跑步方式。但是,使用这种方法,组织中的每个应用程序最终都将拥有自己的身份验证和授权机制。建议的方法是"授权代码"授予类型。另外,在我之前的回答中,我建议使用浏览器本地存储来存储认证令牌。然而,我开始相信饼干是实现这一目标的正确选择。在这个stackoverflow答案中,我详细说明了我的原因、授权代码授予类型实现方法、安全性考虑等。
我认为下面的方法可以用于REST服务身份验证:
创建一个登录restful API以接受用于身份验证的用户名和密码。在传输过程中,使用HTTP POST方法来防止缓存和安全性方面的SSL成功认证后,API返回两个JWT—一个访问令牌(更短的有效期,比如30分钟)和一个刷新令牌(更长的有效期,比如24小时)。
客户端(基于Web的UI)将JWT存储在本地存储中,并且在随后的每个API调用中,都将访问令牌传递到"authorization:bearer access token"头中。
API通过验证签名和到期日期来检查令牌的有效性。如果令牌有效,请检查用户(它将JWT中的"Sub"声明解释为用户名)是否可以通过缓存查找访问API。如果用户被授权访问API,则执行业务逻辑
如果令牌过期,API返回HTTP响应代码400
客户端在接收到400/401时,使用"authorization:bearer refresh token"头中的刷新令牌调用另一个RESTAPI,以获取新的访问令牌。
接收带有刷新令牌的调用时,通过检查签名和到期日期来检查刷新令牌是否有效。如果刷新令牌有效,则从数据库刷新用户的访问权限缓存,并返回新的访问令牌和刷新令牌。如果刷新令牌无效,则返回HTTP响应代码400
如果返回新的访问令牌和刷新令牌,请转到步骤2。如果返回HTTP响应代码400,则客户端假定刷新令牌已过期,并向用户请求用户名和密码。
注销时,清除本地存储
使用这种方法,我们将执行每30分钟加载一次具有用户特定访问权限详细信息的缓存的昂贵操作。因此,如果一个访问被撤销或被授予了新的访问权,则需要30分钟来反映或注销,然后登录。
我认为RESTful身份验证涉及将身份验证令牌作为请求中的参数传递。API使用apikey就是一个例子。我不认为使用cookie或HTTP认证是合格的。
- 应避免使用cookie和http auth,因为csrf存在漏洞。
这就是做到这一点的方法:使用OAuth2.0登录。
只要它支持OAuth,就可以使用除Google之外的其他身份验证方法。
- 没有https,OAuth2不安全,也不无状态。
- 没有https没有什么是安全的。
- @如果证书链断开,craig和https也可能不安全,这可能有助于提高安全性-en.wikipedia.org/wiki/bullrun(解密程序);)
- @Arnaudbouchez请澄清拥有一个断开的证书链对更大的好处是什么?我不明白你要去哪儿。;)
- @克雷格,请点击链接,尽情享受吧!在我的评论中,这种"更大的好处"的方法显然是愤世嫉俗的:像牛头鲸一样的系统是为我们所热爱和信任的政府的"我们自己的好处"而设计的。
- @Craig我的观点是,即使是HTTPS也不是完全安全的,所以OAuth2是一个坏标准。如果您的HTTPS由于证书链断开而受到破坏,因为只有服务器经过身份验证(通常没有相互身份验证),您可以对服务器进行个人验证并执行中间人攻击。然后,MIM服务器将截获OAuth2令牌的纯值,并使用它将假请求伪造到真正的服务器。
- @Arnaudbouchez明白了,他说:"为了更大的利益",愤世嫉俗。
- 所以,https,假设一个完整的证书链(你的浏览器会警告你),假设一个根证书没有被破坏,假设一个站点没有从http重定向到https,从而启用sslstrip攻击(如果用户努力的话,因为sslstrip不会欺骗浏览器认为它有一个安全的连接),而不是至少现在,https还不错。一个突出的问题是愚蠢的应用程序开发人员故意绕过证书链验证,因为很难纠正它。但这是在应用程序开发人员身上,而不是在HTTPS上。不难。
- @在移动应用程序Craig上,VPN代理可以发送HTTPS进行丢弃,除非完成了SSL固定。
使用一个公钥基础结构,其中一个密钥的注册涉及到适当的绑定,确保公钥以一种确保不可拒绝性的方式绑定到它被分配到的个人。
请参阅http://en.wikipedia.org/wiki/public_key_infrastructure。如果您遵循正确的PKI标准,不正确使用被盗钥匙的人或代理可以被识别并锁定。如果代理需要使用证书,那么绑定就变得非常紧密。一个聪明、行动迅速的小偷可以逃走,但他们会留下更多的碎屑。
以我的理解回答这个问题…
使用REST的身份验证系统,这样您就不需要实际跟踪或管理系统中的用户。这是通过使用http方法post、get、put、delete完成的。我们采用这4种方法,并将它们从数据库交互的角度考虑为创建、读取、更新、删除(但是在Web上,我们使用post和get,因为这正是锚标记当前支持的功能)。因此,将post和get视为我们的create/read/update/delete(crud),然后我们可以在Web应用程序中设计路线,从而推断出我们正在实现的crud的操作。
例如,在Ruby on Rails应用程序中,我们可以构建我们的Web应用程序,这样,如果登录的用户访问http://store.com/account/logout,那么该页面的get可以被视为试图注销的用户。在Rails控制器中,我们将在中构建一个操作,将用户注销并发送回主页。
登录页面上的get将生成一个表单。登录页面上的日志将被视为登录尝试,并获取日志数据并使用它进行登录。
对我来说,这是一种使用映射到其数据库含义的HTTP方法的实践,然后在构建身份验证系统时记住,您不需要传递任何会话ID或跟踪会话。
我还在学习——如果你发现我说的任何错误,请纠正我,如果你学到更多,请把它贴在这里。谢谢。
安全任何Web应用程序的有效提示
如果您想保护应用程序的安全,那么一定要从使用HTTPS而不是HTTP开始,这样可以确保在您和用户之间创建一个安全的通道,以防止嗅探来回发送给用户的数据,这将有助于保持交换数据的机密性。
您可以使用JWT(JSON Web令牌)来保护RESTful API,与服务器端会话相比,这有很多好处,主要好处是:
1-更具可扩展性,因为您的API服务器不必为每个用户维护会话(当您有许多会话时,这可能是一个很大的负担)
2-JWT是独立的,具有定义用户角色的声明,例如,他可以访问和发布的内容在日期和到期日期(之后JWT将无效)
3-如果您有多个API服务器,则可以更轻松地处理跨负载平衡,因为您不必共享会话数据,也不必配置服务器将会话路由到同一服务器,只要JWT请求命中任何服务器,都可以对其进行身份验证和授权。
4-减少对数据库的压力,而且您不必经常存储和检索每个请求的会话ID和数据。
5-如果您使用强密钥签署JWT,则JWT不能被篡改,因此您可以信任随请求发送的JWT中的声明,而无需检查用户会话以及他是否获得授权,您只需检查JWT,然后就可以知道该用户可以做什么。
许多库提供了用大多数编程语言创建和验证JWT的简单方法,例如:在node.js中,最流行的是jsonwebtoken
由于REST API通常旨在保持服务器无状态,因此JWT与该概念更兼容,因为与使服务器具有状态的会话相比,每个请求都使用自包含的授权令牌(JWT)发送,而服务器不必跟踪用户会话,因此它记住用户及其角色。会话也被广泛使用,并有其优点,您可以根据需要搜索。
需要注意的一点是,您必须使用https安全地将JWT交付给客户机,并将其保存在安全的地方(例如本地存储中)。
您可以通过此链接了解有关JWT的更多信息