在不重新发明*的情况下保护REST API

问题描述:

设计REST API时,通常先验证用户身份?在不重新发明*的情况下保护REST API

我要找的典型使用情况是:

  • 用户希望得到的数据。当然很酷,我们喜欢分享!获取一个公共API密钥并阅读!
  • 用户想要存储/更新数据......哇等等!你是谁,你能做到吗?

我想构建一次,并允许说一个网络应用程序,Android应用程序或iPhone应用程序来使用它。

一个REST API似乎是这样

要求要说明我的问题,我会用一个简单的例子,一个合乎逻辑的选择。

我有一个数据库中的项目,它有一个评分属性(整数1到5)。

如果我理解REST正确我会实现使用我选择的返回CSV,XML或JSON这样的语言GET请求:

http://example.com/product/getrating/{id}/ 

说我们挑JSON我们返回:

{ 
    "id": "1", 
    "name": "widget1", 
    "attributes": { "rating": {"type":"int", "value":4} } 
} 

这对于面向公众的API来说很好。我得到那部分。

我在哪里有很多问题,我该如何将它与安全模型相结合?我习惯了网络应用程序的安全性,我有一个会话状态随时可以识别我的用户,所以我可以控制他们可以做什么,无论他们决定发送给我什么。据我了解,这不是RESTful,所以在这种情况下将是一个不好的解决方案。

我会尝试使用另一个使用相同项目/评级的例子。

如果用户“JOE”想要一个评级添加到项目

这可以通过使用来完成:

http://example.com/product/addrating/{id}/{givenRating}/ 

在这一点上我想存储的数据说“ JOE“给出了产品{id}的评分{givenRating}。

问:我怎么知道请求来自“JOE”而不是“BOB”。

此外,如果是用户的电话号码等更明智的数据呢?

到目前为止,我已经得到了什么是:

1)使用内置的HTTP的功能,在每个请求进行身份验证,无论是普通的HTTP或HTTPS。

这意味着,每一个要求,现在采取的形式是:

https://joe:[email protected]/product/addrating/{id}/{givenRating}/ 

2)使用诸如亚马逊的S3与私人和公共密钥的方法:http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/

3)仍要使用一个Cookie,并打破REST的无状态部分。

第二种方法对我来说似乎更好,但我还是想知道我是否真的必须重新创造这整个事情?散列,存储,生成密钥等都由我自己?

这听起来很像在典型的Web应用程序中使用会话并且自己重写整个堆栈,通常我的意思是“你做错了”,特别是在处理安全性时。

编辑:我想我应该提到OAuth以及。

+4

如果您发送每个请求的用户名和密码,请使用HTTPS **。 –

+51

与安全无关,但RESTful API不会使用'getrating'和'andrating';它只是“评级”,你会GET,POST,PUT或DELETE到该资源。 – Duncan

编辑5年以后

使用的OAuth2!

以前版本

没有,绝对没有必要使用Cookie。它不如HTTP摘要,OAuth或亚马逊的AWS(这不难复制)安全一半。

您应该查看Cookie的方式是,它与Basic/Digest/OAuth /以较高者为准,但不太合适。

但是,只要会话cookie的内容不影响您从服务器返回的资源内容,我并不认为使用cookie会违反REST风格的原则本身

饼干是邪恶的,停止使用它们。

+2

我没有发现亚马逊的方式难以复制每一个说......像我没有发现从头开始写JavaScript“硬”,但jQuery肯定帮助写好。阅读它让我想知道是不是有一个抽象的框架? – jfrobishow

+1

谷歌它。我为AWS编写了一个实现,但它并不完整,我相信:http://code.google.com/p/sabredav/source/browse/lib/Sabre/HTTP/AWSAuth.php – Evert

+2

对不起,但答案不正确。 Cookie和HTTP摘要是互补的但是正交的 - 您可以使用第二个来验证用户并发布cookie。与OAuth相比,基于cookie的安全性在您拥有跨域服务时不起作用,或者您让其他不受信任的人将客户端写入您的服务(涉及第三方)并希望允许您的用户撤销应用程序访问。但在其他情况下,它的工作方式与OAuth完全相同,您可以将Cookie作为OAuth访问令牌进行考虑,这也是您需要在某处存储的方式。 – zihotki

不要担心“RESTful”,担心安全问题。以下是我的工作方式:

步骤1:用户使用凭据访问身份验证服务。

步骤2:如果凭证检出,返回一个指纹,会话ID等等,并将它们弹出到共享内存中以便以后快速检索或使用数据库,如果您不介意将几毫秒添加到您的Web服务周转时间。

步骤3:向每个Web服务脚本的顶部添加一个入口点调用,该脚本验证每个 Web服务请求的的指纹和会话ID。

第4步:如果指纹和会话ID无效或超时重定向到身份验证。

这样说的:

RESTful Authentication

+3

但是,那么在每次“会话”过期之前访问API之前都不要强制用户登录?如果是移动设备,你会怎么做?给他们一个永久的“钥匙”,这样他们就不必每次使用应用程序时都使用API​​登录? – jfrobishow

+1

我强制他们登录。它不是那个,就是使用cookie,或者将指纹映射到他们的UDID,但是UDID就意味着用户必须从同一个设备访问服务。 –

+0

关于第3步:这意味着如果我使用的是“控制器”内使用“Actions”的MVC框架,我应该在每个Action中加入两个额外的参数(指纹和sessionid)? – sports

编辑3年后

我完全同意埃弗特,使用OAuth2使用HTTPS,不推倒重来! :-)

通过更简单的REST API - 不适用于第三方客户端 - JSON Web Tokens也可以。

以前版本

仍要使用一个Cookie,打破REST的无状态的一部分。

不要使用会话,使用会话您的REST服务将不会很好的扩展......这里有两种状态:应用程序状态(或客户端状态或会话)和资源状态。应用程序状态包含会话数据,并由REST客户端维护。资源状态包含资源属性和关系,并由REST服务维护。你可以很容易地决定一个特定的变量是应用程序状态还是资源状态的一部分。如果数据量随着活动会话的数量而增加,则它属于应用程序状态。因此,例如,当前会话的用户身份属于应用程序状态,但用户列表或用户权限属于资源状态。

因此,REST客户端应该存储识别因子并将其发送给每个请求。不要将REST客户端与HTTP客户端混淆。他们不一样。如果REST客户端使用curl,它也可以在服务器端,或者它可以创建例如服务器端http only cookie,它可以通过CORS与REST服务共享。唯一重要的是REST服务必须通过每个请求进行身份验证,因此您必须随每个请求一起发送凭据(用户名,密码)。

  • 如果您编写客户端REST客户端,则可以使用SSL + HTTP身份验证完成此操作。在这种情况下,您可以在服务器上创建credentials -> (identity, permissions)缓存以加快身份验证。请注意,如果您清除缓存并且用户发送相同的请求,则它们将得到相同的响应,只需要更长的时间。您可以将其与会话进行比较:如果您清除会话存储区,则用户将得到一个status: 401 unauthorized响应...
  • 如果您编写服务器端REST客户端,并通过curl将识别因子发送到REST服务, 2个选择。您也可以使用http auth,或者您可以在REST客户端中使用会话管理器,但不能在REST服务中使用。
  • 如果有人不信任地写入您的REST客户端,那么您必须编写一个应用程序来对用户进行身份验证,并为他们提供可用性以决定他们是否要将权限授予不同的客户端。 Oauth是一个已经存在的解决方案。 Oauth1更安全,oauth2不太安全但更简单,我想这个问题还有其他几个解决方案......你不必重新创建这个。有完整的使用oauth的认证和授权解决方案,例如:wso identity server

饼干不一定是坏的。您可以以RESTful方式使用它们,直到它们保持客户端状态并且服务仅保持资源状态。例如,您可以将购物车或首选的分页设置存储在Cookie中...

+1

这是怎么回事?不要担心是“RESTful”,担心安全问题。 –

+0

太晚了,我不知道你在说什么,对不起。 :D明天我会读这篇文章,我不记得它... – inf3rno

+2

我设法再次阅读这篇文章。叶普,我认为这是因为我的帖子比你提到的帖子延迟了2年。就这样,祝你有个愉快的夜晚! :-) – inf3rno