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

时间:2011-08-30 02:28:46

标签: web-services security api rest

设计REST API时,首先验证用户是否常见?

我正在寻找的典型用例是:

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

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

REST API似乎是具有此类要求的合理选择

为了说明我的问题,我将使用一个简单的例子。

我在数据库中有一个项目,该项目具有评级属性(整数1到5)。

如果我正确理解REST,我会使用我选择的语言实现GET请求,返回csv,xml或json,如下所示:

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:joepassword@example.com/product/addrating/{id}/{givenRating}/

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

3)无论如何使用cookie并打破REST的无状态部分。

第二种方法对我来说似乎更好,但我想知道我真的需要重新发明这一切吗?所有由我自己进行哈希,存储,生成密钥等等?

这听起来很像在典型的Web应用程序中使用会话并自己重写整个堆栈,这通常意味着“你做错了”,尤其是在处理安全问题时。

编辑:我想我也应该提到OAuth。

3 个答案:

答案 0 :(得分:21)

不要担心“RESTful”,担心安全性。我是这样做的:

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

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

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

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

请阅读:

RESTful Authentication

答案 1 :(得分:21)

5年后编辑

使用OAuth2!

以前的版本

不,绝对不需要使用cookie。它不像HTTP摘要,OAuth或亚马逊的AWS那样安全一半(不难复制)。

您应该查看Cookie的方式是,它是一个身份验证令牌,与Basic / Digest / OAuth /中的任何一个一样多,但不太合适。

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

Cookies是邪恶的,不再使用它们。

答案 2 :(得分:8)

3年后编辑

我完全同意Evert,使用OAuth2和HTTPS,并且不要重新发明轮子! :-)

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

以前的版本

  

无论如何使用cookie并打破REST的无状态部分。

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

因此,REST客户端应存储标识因子,并在每次请求时发送它们。不要将REST客户端与HTTP客户端混淆。他们不一样。如果REST客户端使用curl,它也可以在服务器端,或者它可以创建例如服务器端仅http的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

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