RESTful身份验证


745

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


3
当我使用RESTful身份验证时,我发现了十二个RoR插件。我假设这些不是您想要的。如果不是RoR,那是什么语言?什么网络服务器?
S.Lott

2
如果您使用HTTPS,这不会是完全错误的。完整的HTTP请求以及URL将被加密。
巴拉特·哈特里

4
@BharatKhatri:是的。我永远不会在用户可见的URL中传递敏感信息。出于实际目的,此信息更有可能泄漏。HTTPS不能帮助意外泄漏。
Jo So

2
@jcoffland:真正的RESTful身份验证是什么意思?我很感兴趣,因为我刚刚从接受的答案中实现了第三种方法,但是我对此并不满意(我不喜欢URL中的其他参数)。
BlueLettuce16

4
有些人使用jwt.io/introduction解决此问题。.我现在正在研究此问题以解决我的问题:stackoverflow.com/questions/36974163/… >>希望此方法能正常工作。
2016年

Answers:


586

如何在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,这是除了任何身份验证方案之外所必需的。


5
如果您Cookie用作更好的替代品,则HTTP Basic Auth可以使用一种使身份验证到期并具有注销功能的方法来进行真正的无状态身份验证。一个示例实现可以使用Emulated-HTTP-Basic-Auth具有与真实HTTP Basic Auth相似的值的被调用的cookie ,并另外设置到期时间。然后可以通过删除该cookie来实现注销。我猜想,任何能够支持HTTP基本身份验证的客户端也可以支持以这种方式完成的cookie身份验证。
Mikko Rantalainen

4
@MikkoRantalainen但是,正如我所写的那样,该cookie仍将由服务器管理。它是某种无状态的,但不是“纯”无状态的。在所有情况下,您都需要专用于客户端登录/注销的JavaScript代码,例如使用HTTP Digest Auth,这是完全可行的 -很好的主意,但是在这里没有太大的好处,可以重新发明轮子。
Arnaud Bouchez,

4
我声称服务器实现用于配置标头的UI和逻辑,但是标头本身是无状态的。为API设计的客户端可以跳过使用服务器帮助来配置标头,而仅传递类似于HTTP Basic Auth的必需信息。我的观点是,常见的UA(浏览器)对Basic Auth的实现如此差,无法使用。可以使用服务器在另一个标头(Cookie)中为相同内容提供的仿真。
Mikko Rantalainen


7
仅当服务器通过发送回401未经授权的响应请求HTTP授权时,才会出现难看的HTTP授权密码提示。如果您不喜欢它,只需发送403 Forbidden。错误页面可能包括登录方法或指向该链接的链接。但是,针对cookie和http身份验证(无论状态是服务器端还是客户端)的最大争论是,它们容易受到跨站点请求伪造的攻击。因此,最好的方法是自定义授权方案,自定义授权标头或自定义GET或POST参数。
Dobes Vandermeer 2014年

418

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

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

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

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

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

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

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

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

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

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


68
这是一个务实的答案,并且建议的解决方案有效。但是,在同一句子中使用术语“ RESTful”和“ session”只是错误的(除非在;之间也有“ not”)。换句话说:使用会话的任何Web服务都不是RESTful(根据定义)。不要误会我的意思-您仍然可以使用此解决方案(YMMV),但是术语“ RESTful”不能用于此。我推荐一本关于REST的O'Reilly书,该书非常易读,并深入解释了该主题。
johndodo

23
@skrebbel:纯REST解决方案会在每次请求资源时发送身份验证数据,这并不完美(HTTP Auth会这样做)。提出的解决方案可以工作,并且对于大多数用例而言更好,但是它不是RESTful的。无需战争,我也使用此解决方案。我只是不声称它是RESTful。:)
johndodo 2011年

94
哦,拜托,举个例子。那是什么其他方式,效果很好?我真的很想知道。当然不是HTTP Auth,没有关闭浏览器就无法注销,没有大量浏览器特定的,与未来不兼容的JS,就不能提供体面的登录UX。我不太关心“完全RESTful”还是“几乎RESTful”以及整个相关的宗教辩论,但是如果您说有几种方法,应该将它们拼出来。
skrebbel 2011年

15
使用真实世界的用户代理(也称为“浏览器”)进行的真正RESTful身份验证由包含HTTP身份验证值的cookie组成。这样,服务器可以提供用于输入登录名和密码的UI,并且服务器可以强制注销(通过删除cookie)。另外,服务器必须使用临时重定向到登录屏幕,并且在成功登录后使用临时重定向回到以前的位置,而不是在身份验证失败时响应401以要求登录。另外,服务器必须将注销操作(POST表单)嵌入几乎每个登录用户的页面。
Mikko Rantalainen'2

15
我认为在同一句子中使用“ restful”和“ session”不会有任何问题,只要很明显该会话仅存在于客户端即可。我不确定为什么对这个概念如此重要。
乔·菲利普斯

140

这里的好人已经对这个话题说了足够多的话。但是这是我的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,那么您就干了。


3
主席先生,您的解释如此优美,以至于我对当前的基本问题有一个清晰的认识。你就像佛陀!我可能会补充说,通过在传输层使用HTTPS,我们甚至可以阻止“中间人”攻击,因此没有人会劫持我的标识符密钥(如果选择了Way-1)
Vishnoo Rath 2014年

难道不是一台机器总是在进行身份验证吗?人工操作不会给密码带来麻烦,对于正确合理化安全性的用户来说,这是一个不幸的烦恼。对我而言,这是开发人员的问题,他们希望如何使机器正常工作。
Todd Baur 2014年

9
我读了你的答案;在您的解决方案中,对于用户点击在浏览器上发起的每个Web请求,都需要将“身份验证令牌”发送回用户点击所调用的任何API。然后怎样呢?API对令牌执行检查。反对什么?反对某种“令牌存储”,该令牌存储维护该令牌是否有效。您是否不同意“令牌存储”将成为“国家”的管理者?确实,无论您如何看待它,某个地方的人都必须了解有关在用户活动中传递的“令牌”的一些信息。那就是状态信息所在的地方。
金兹

5
“无状态”服务的真正含义是该特定服务器组件(CRUD API)不携带任何状态。他们不会从另一个用户中识别一个用户,而是在一个事务中完整地完成用户请求。那就是无国籍。但是某个地方的某人必须坐在那里并通过判断该用户是否有效。没有其他方法可以执行此操作;键或密码等。从用户方传递过来的任何东西都必须经过身份验证和授权。
金兹

1
您不见了Way-3,混合方法。客户端以的身份登录,Way-2但与一样Way-1,未针对任何服务器端状态检查凭据。无论如何,都会像中一样创建auth令牌并将其发送回客户端Way-2。稍后使用不对称加密检查此令牌的真实性,而无需查找任何客户端特定状态。
jcoffland 2015年

50

这是一个真正且完全RESTful的身份验证解决方案:

  1. 在身份验证服务器上创建一个公用/专用密钥对。
  2. 将公钥分配给所有服务器。
  3. 当客户端认证时:

    3.1。发出包含以下内容的令牌:

    • 到期时间
    • 用户名(可选)
    • 用户IP(可选)
    • 密码的哈希(可选)

    3.2。用私钥加密令牌。

    3.3。将加密的令牌发送回用户。

  4. 当用户访问任何API时,他们还必须传递其auth令牌。

  5. 服务器可以通过使用auth服务器的公钥解密令牌来验证令牌是否有效。

这是无状态/ RESTful身份验证。

请注意,如果包含密码哈希,则用户还将发送未加密的密码以及身份验证令牌。服务器可以通过比较散列来验证密码是否与用于创建身份验证令牌的密码匹配。使用HTTPS之类的安全连接是必要的。客户端上的Javascript可以处理获取用户的密码并将其存储在客户端或Cookie中的方式,可以将其存储在内存或Cookie中,并可能使用服务器的公共密钥进行了加密。


5
如果有人握住该身份验证令牌并假装为客户端调用API,该怎么办?
阿比迪

2
@Abidi,是的,这是个问题。您可能需要密码。密码的哈希可以包含在身份验证令牌中。如果有人能够窃取令牌,那么它将容易受到离线暴力攻击。如果选择了强密码短语,那将不是问题。请注意,如果您使用https令牌盗窃,将要求攻击者首先获得对客户端计算机的访问权限。
jcoffland 2014年

1
因为只有身份验证服务器才能知道私钥。其他服务器可以仅通过知道公钥和用户令牌来认证用户。
jcoffland 2014年

1
非对称加密和解密比对称加密要慢一个数量级(计算强度更大),让服务器在每次调用时都使用公钥解密令牌是一个巨大的性能瓶颈。
Craig

3
@jcoffland,您确实在这里提升了您的答案(反复:-),但是我不禁评论在每个呼叫上使用非对称加密的性能问题(计算强度)。我只是看不到具有任何扩展能力的解决方案。查找HTTPS和SPDY协议。保持连接开放(HTTP保持活动状态,即状态)并在同一连接上分批提供多个资源(更多状态)是不言而喻的,当然SSL本身仅使用非对称加密来交换对称密码(也说明)。
Craig

37

老实说,我在这里看到了不错的答案,但是令我感到困扰的是,有人将整个无状态概念推向了一个教条主义的极端。这让我想起那些只想拥抱纯OO的Smalltalk老粉丝,如果不是对象,那么您做错了。休息一下

RESTful方法应该使您的生活更轻松,并减少会话的开销和成本,请尝试遵循它,因为这样做是明智的选择,但是在您遵循某个学科(任何学科/指南)的那一刻,不再提供预期的收益,那么您做错了。当今一些最好的语言同时具有功能编程和面向对象的功能。

如果您要解决问题的最简单方法是将身份验证密钥存储在cookie中,然后将其发送到HTTP标头,则可以这样做,只是不要滥用它。请记住,当会话变得繁重时,它是不好的,如果您的所有会话都由包含密钥的短字符串组成,那有什么大不了的呢?

我乐于接受评论中的更正,但是(到目前为止)我只是不明白使我们的生活变得痛苦的原因,只是避免在服务器中保留大量的哈希字典。


2
人们并没有试图禁止您使用会话。您可以自由地这样做。但是,如果这样做,则不是REST。
安德烈·卡尔达斯

6
@AndréCaldas不是REST,就不是以某种语言拥有函数或原始类型的方式。我并不是说召开会议是明智的。我只是就遵循一系列做法提供自己的意见,以使它们不再为某人带来好处。(顺便说一句,请注意我没有反对您的言论,但是,我不会说它不是REST,我会说它不是 REST)。
arg20 2013年

那么,如果不是RESTful,我们怎么称呼它?而且,如果请求中包含会话ID,那么与包含用户ID的请求一样无状态吗?为什么用户ID是无状态的,而会话ID是有状态的?
mfhholmes 2013年

1
Cookies容易受到跨站点请求伪造的侵害,因此它们更容易造成安全漏洞。最好使用浏览器不会自动发送的内容,例如自定义标头或自定义授权方案。
Dobes Vandermeer 2014年

1
实际上,尝试成为无状态的不是教条主义,而是关于SOA本身的一个常见概念。服务应始终受益于脱机和无状态:在实践中,它可以简化扩展,可用性和可维护性。当然,应该尽可能地多,最终您将需要一些“编排服务”以将这些无状态服务管理为有状态的实用方法。
Arnaud Bouchez,2015年

32

首先,一个RESTful Web服务是无状态(或者换句话说,无会话)。因此,RESTful服务不存在也不应该包含会话或cookie的概念。在RESTful服务中进行身份验证或授权的方法是使用RFC 2616 HTTP规范中定义的HTTP授权标头。每个单个请求都应包含HTTP授权标头,并且该请求应通过HTTP(SSL)连接发送。这是在HTTP RESTful Web服务中进行身份验证和验证请求授权的正确方法。我已经在Cisco Systems的Cisco PRIME Performance Manager应用程序中实现了RESTful Web服务。作为该Web服务的一部分,我还实现了身份验证/授权。


5
HTTP身份验证仍然需要服务器跟踪用户ID和密码。这不是完全无状态的。
jcoffland 2014年

21
从每个意义上来说,每个请求本身都是有效的,而无需先前请求的任何要求,这是无状态的。如何在服务器上实现此操作则是另一回事,如果身份验证成本很高,则可以进行一些缓存并在缓存未命中时重新进行身份验证。很少有服务器是完全无状态的,其中输出仅是输入的函数。它通常是对某种状态的查询或更新。
Erik Martino 2014年

3
不对。在这种情况下,您的所有请求都需要先前交易的状态,即用户注册。我不明白为什么人们总是试图说存储在服务器上的用户名和密码不是服务器端状态。看我的答案。
jcoffland 2014年

1
@jcoffland同样,您的解决方案在很大程度上依赖于API服务器解密签名令牌的能力。我认为这种方法不仅太具体了,而且有点复杂,以至于不能被当作方法R。菲尔丁想到了要解决RESTful身份验证的问题。
Michael Ekoka 2014年

2
@jcoffland您是否了解非对称加密在计算密集度(因此在资源密集度和速度上非常慢)方面有多深?您正在谈论的方案是对每个单个请求使用非对称加密。HTTPS的最慢方面(没有任何限制)是初始握手,该握手涉及创建公钥/私钥以非对称方式加密共享密钥,该共享密钥随后用于对称地加密所有随后的通信。
Craig 2015年

22

当然,这与“会话密钥”无关,因为它通常用于指代在REST的所有约束内执行的无会话身份验证。每个请求都是自描述的,携带足够的信息以自行授权请求,而没有任何服务器端应用程序状态。

解决此问题的最简单方法是从RFC 2617中 HTTP的内置身份验证机制开始。


HTTP身份验证要求服务器存储用户名和密码。这是服务器端状态,因此不是严格的REST。看我的答案。
jcoffland 2014年

3
@jcoffland:两种说法都不是真的。First HTTP Auth不需要服务器存储密码。而是存储密码的哈希(建议使用8轮以上的加密)。其次,服务器没有任何状态,因为授权标头随每个请求一起发送。而且,如果您将存储的密码哈希视为状态,则它们的状态不会超过存储的公共密钥。
鲍里斯·B。

1
@Boris B.,是的,我知道密码存储为哈希值。哈希密码仍然是客户端特定的状态。如我的解决方案中所述,与存储公用密钥的区别在于,只有一个公用密钥,即身份验证服务器的公用密钥。这与为每个用户存储密码哈希非常不同。如果服务器为每个用户存储一个密码,那么无论如何修饰它,它都将按用户状态存储,而不是100%REST。
jcoffland 2014年

7
我不认为将用户哈希密码存储在服务器上不应视为服务器端状态。用户是资源,包含名称,地址或哈希密码之类的信息。
Codepunkt 2014年

15

@skrebel(http://www.berenddeboer.net/rest/authentication.html)提到的“非常有见识的”文章讨论了一种复杂但确实很破损的身份验证方法。

您可以尝试访问该页面(应该仅对经过身份验证的用户可见)http://www.berenddeboer.net/rest/site/authenticated.html,而无需任何登录凭据。

(对不起,我无法对答案发表评论。)

我会说REST和身份验证根本不混在一起。REST表示无状态,但“已认证”是一种状态。您不能将它们放在同一层。如果您是RESTful的拥护者并且对状态不满意,则必须使用HTTPS(即将安全性问题留给另一层)。


Stripe.com原本说在休息和验证您的评论不混合..
埃里克

无状态仅指服务器,而不是客户端。客户端可以记住会话的所有状态,并发送与每个请求相关的内容。
Dobes Vandermeer 2014年

最终,有人会说一些道理,但是使用公钥加密可以进行无状态身份验证。看我的答案。
jcoffland 2014年

1
服务器没有“已认证”状态。它通过超媒体接收信息,并且必须与之一起返回所请求的信息。什么都没有,仅此而已。如果资源受到保护并且需要身份验证和授权,则提供的超媒体必须包含该信息。我不知道在返回资源之前对用户进行身份验证意味着服务器正在跟踪状态的想法来自何处。提供用户名和密码可以很好地视为简单地提供更多过滤参数。
Michael Ekoka 2014年

“我会说REST和身份验证根本不混在一起。” 听起来像是一些常识。除了与身份验证不兼容的系统(当然,“已身份验证”本身是一种状态)的用途有限之外。我觉得我们都在争论实用性和纯粹主义的专制主义的交集,坦率地说,实用性应该是赢家。REST的很多方面都是非常有益的,无需费力地尝试避免针对身份验证的状态,不是吗?
Craig


12

2019年2月16日更新

下面前面提到的方法实质上是OAuth2.0的 “资源所有者密码凭证”授予类型。这是启动和运行的简单方法。但是,使用这种方法,组织中的每个应用程序最终都会拥有自己的身份验证和授权机制。推荐的方法是“授权代码”授予类型。此外,在下面的较早答案中,我建议使用浏览器localStorage来存储身份验证令牌。但是,我已经相信cookie是用于此目的的正确选择。我在这个StackOverflow答案中详细说明了我的原因,授权码授予类型的实现方法,安全性注意事项等。


我认为以下方法可用于REST服务身份验证:

  1. 创建一个登录RESTful API,以接受用于验证的用户名和密码。在传输过程中使用HTTP POST方法来防止缓存和SSL的安全性在成功进行身份验证时,API返回两个JWT-一个访问令牌(有效期较短,例如30分钟)和一个刷新令牌(有效期较长,例如24小时)
  2. 客户端(基于Web的UI)将JWT存储在本地存储中,并且在随后的每个API调用中,都在“授权:承载#访问令牌”标头中传递访问令牌
  3. API通过验证签名和有效日期来检查令牌的有效性。如果令牌有效,请检查用户(它将JWT中的“ sub”声明声明为用户名)是否可以通过缓存查找访问API。如果用户有权访问API,请执行业务逻辑
  4. 如果令牌已过期,则API返回HTTP响应代码400
  5. 客户端在接收到400/401时,将使用“授权:承载#刷新令牌”标头中的刷新令牌调用另一个REST API,以获取新的访问令牌。
  6. 收到带有刷新令牌的呼叫后,通过检查签名和到期日期来检查刷新令牌是否有效。如果刷新令牌有效,请从数据库刷新用户的访问权限缓存,并返回新的访问令牌和刷新令牌。如果刷新令牌无效,则返回HTTP响应代码400
  7. 如果返回了新的访问令牌和刷新令牌,请转到步骤2。如果返回了HTTP响应代码400,则客户端认为刷新令牌已过期,并要求用户输入用户名和密码。
  8. 要注销,请清除本地存储

通过这种方法,我们正在执行昂贵的操作,每30分钟使用用户特定的访问权限详细信息加载缓存。因此,如果撤消访问权限或授予新的访问权限,则需要30分钟的时间进行反映或注销后再进行登录。


因此,您是否会将其用于具有静态网站(例如,由angular制作)的api?以及移动应用程序呢?
Yazan Rawashdeh,

8

这样做的方法是:使用OAuth 2.0登录

您可以使用Google以外的其他身份验证方法,只要它支持OAuth。


1
没有HTTPS,OAuth2也不安全,也没有状态。
2015年

4
没有HTTPS,没有什么是安全的。
Craig

1
@Craig和HTTPS可以不被任一固定,如果证书链被破坏,这可能是更大的好- en.wikipedia.org/wiki/Bullrun_(decryption_program) ;)
阿诺Bouchez

1
@ArnaudBouchez请说明证书链损坏对更大的好处有何影响?我不明白你要去哪里。;)
Craig

@Craig请点击链接,并享受!在我的评论中,这种“更大的好处”方法显然是愤世嫉俗的:类似牛市的体系是我们心爱和信任的政府为“我们自己的利益”而设计的。
Arnaud Bouchez

3

使用其中密钥注册涉及适当绑定的公钥基础结构,可以确保公钥以确保不可否认的方式绑定到分配给它的个人

参见http://en.wikipedia.org/wiki/Public_key_infrastructure。如果您遵循正确的PKI标准,则可以识别出不正确使用被盗密钥的个人或代理商,并将其锁定。如果要求代理使用证书,则绑定会变得非常紧密。一个聪明而迅捷的小偷可以逃脱,但会留下更多的碎屑。


2

根据我的理解回答这个问题...

使用REST的身份验证系统,因此您无需实际跟踪或管理系统中的用户。这是通过使用HTTP方法POST,GET,PUT,DELETE完成的。我们采用这4种方法,并在数据库交互方面将它们视为CREATE,READ,UPDATE,DELETE(但是在网络上,我们使用POST和GET,因为这是锚标记当前所支持的)。因此,将POST和GET作为我们的CREATE / READ / UPDATE / DELETE(CRUD),然后我们可以在Web应用程序中设计路由,从而能够推断出CRUD所要实现的作用。

例如,在Ruby on Rails应用程序中,我们可以构建Web应用程序,这样,如果登录的用户访问http://store.com/account/logout,则该页面的GET可以视为尝试注销的用户。 。在我们的rails控制器中,我们将构建一个动作,将用户注销并发送回首页。

登录页面上的GET将产生一个表格。在登录页面上的POST将被视为登录尝试,并获取POST数据并将其用于登录。

对我来说,这是一种使用映射到其数据库含义的HTTP方法,然后考虑到这一点构建身份验证系统的实践,您无需传递任何会话ID或跟踪会话。

我仍在学习-如果您发现我说错的任何内容,请纠正我,如果您了解更多信息,请在此发布。谢谢。


2

对保护任何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的更多信息

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.