关于休息:RESTful身份验证

RESTful Authentication

RESTful认证意味着什么?它是如何工作的?我在谷歌上找不到一个好的概述。我唯一的理解是您在URL中传递了会话密钥(rememberal),但这可能是非常错误的。


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


我怀疑那些狂热地叫喊"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头内容仅用于处理服务器端资源,就像接受语言可能用于访问翻译资源等。我觉得是一样的,但也许其他人不一样?你们觉得怎么样,伙计们?


在这个问题上,这里的好人已经说得够多了。但这是我的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,你就做了你的工作。好的。好啊。


    这里有一个真正的、完全静止的身份验证解决方案:

  • 在身份验证服务器上创建公钥/私钥对。
  • 将公钥分发到所有服务器。
  • 当客户端进行身份验证时:

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

    • 有效期
    • 用户名(可选)
    • 用户IP(可选)
    • 密码哈希(可选)

    3.2。用私钥加密令牌。

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

  • 当用户访问任何API时,他们还必须传递其身份验证令牌。

  • 服务器可以通过使用身份验证服务器的公钥对令牌进行解密来验证令牌是否有效。
  • 这是无状态/RESTful身份验证。

    注意,如果包含密码哈希,用户还将发送未加密的密码和身份验证令牌。服务器可以通过比较哈希来验证密码是否与用于创建身份验证令牌的密码匹配。使用类似https的安全连接是必要的。客户机端的javascript可以处理获取用户密码并将其存储在客户机端,或者存储在内存中,或者存储在cookie中,可能使用服务器的公钥加密。


    老实说,我在这里看到了很好的答案,但有一点让我感到困扰的是,当有人将整个无状态的概念推向极端时,它就会变得教条化。它让我想起那些只想拥抱纯OO的旧的Smalltalk粉丝,如果某个东西不是一个对象,那么你就做错了。让我休息一下。

    休息的方法应该让你的生活更轻松,减少会议的开销和费用,试着遵循它,因为这是一件明智的事情,但一旦你遵循一个纪律(任何纪律/指导方针)到了极端,它不再提供它的目的,那么你就错了。今天一些最好的语言既有函数式编程,也有面向对象的。

    如果解决问题的最简单方法是将身份验证密钥存储在cookie中并发送到HTTP头上,那么就这样做,不要滥用它。记住,当会话变得沉重和庞大时,它们是不好的,如果所有会话都由一个包含键的短字符串组成,那么有什么大不了的?

    我愿意接受评论中的更正,但我不认为(到目前为止)仅仅是为了避免在服务器上保存一本大的哈希字典而让我们的生活变得悲惨。


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

    鲁本斯·戈麦斯。


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

    最简单的方法是从RFC2617中的HTTP内置身份验证机制开始。


    @skrebel提到的"非常有洞察力"的文章(http://www.berenddeboer.net/rest/authentication.html)讨论了一种复杂但真正失败的身份验证方法。

    您可以尝试访问http://www.berenddeboer.net/rest/site/authenticated.html,而不使用任何登录凭据。

    (抱歉,我无法对答案发表评论。)

    我会说,REST和身份验证只是不混合。rest表示无状态,但"authenticated"是状态。不能将它们都放在同一层。如果你是一个宁静的倡导者并且不喜欢国家,那么你必须使用HTTPS(即,将安全问题留给另一层)。


    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认证是合格的。


    这就是做到这一点的方法:使用OAuth2.0登录。

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


    使用一个公钥基础结构,其中一个密钥的注册涉及到适当的绑定,确保公钥以一种确保不可拒绝性的方式绑定到它被分配到的个人。

    请参阅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的更多信息