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

Posted

技术标签:

【中文标题】在不重新发明***的情况下保护 REST API【英文标题】:Securing REST API without reinventing the wheel 【发布时间】:2011-11-06 11:24:47 【问题描述】:

在设计 REST API 时,通常首先对用户进行身份验证吗?

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

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

我想构建一次并允许网络应用、android 应用或 iPhone 应用使用它。

REST API 似乎是符合此类要求的合乎逻辑的选择

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

我在数据库中有一个项目,它有一个 rating 属性(整数 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”想要为 item

添加 rating

这可以使用:

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) 使用像 Amazon 的 S3 这样的方法,带有私钥和公钥:http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/

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

第二种方法对我来说似乎更好,但我想知道我真的必须重新发明整个事情吗?自己散列、存储、生成密钥等?

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

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

【问题讨论】:

如果您在每次请求时都发送用户名和密码,请使用 HTTPS 与安全无关,但 RESTful API 不会使用 getratingandrating;它只是 rating,您可以 GET、POST、PUT 或 DELETE 到该资源。 【参考方案1】:

5 年后编辑

使用 OAuth2!

以前的版本

不,绝对不需要使用 cookie。它的安全性不如 HTTP Digest、OAuth 或亚马逊的 AWS(不难复制)。

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

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

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

【讨论】:

我不觉得亚马逊的方式很难复制...就像我不觉得从头开始编写 javascript 很“难”,但 jQuery 确实有助于编写它。读到它让我想知道是否有一个框架来抽象它? 谷歌它。我为 AWS 编写了一个实现,但我相信它并不完整:code.google.com/p/sabredav/source/browse/lib/Sabre/HTTP/… 对不起,答案不正确。 Cookies 和 HTTP Digest 是互补但正交的 - 您可以使用第二个来验证用户并发出 cookie。与 OAuth 相比,当您拥有跨域服务,或者您让其他不受信任的人将客户端写入您的服务(涉及第 3 方)并希望允许您的用户撤销应用程序访问权限时,基于 cookie 的安全性将不起作用。但在其他情况下,它的工作原理与 OAuth 完全相同,您可以将 cookie 视为 OAuth 访问令牌,顺便说一下,您也需要将其存储在某个地方。 我的答案是在 OAuth2 之前写的,当时每个 OAuth 令牌都是与请求相关的一堆信息的摘要。对于 OAuth2 持有者而言,情况并非如此,这确实使其与 Cookie 中的令牌相当。【参考方案2】:

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

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

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

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

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

阅读:

RESTful Authentication

【讨论】:

但是,每次“会话”到期时,您不会强制用户在访问 API 之前登录吗?如果是移动设备,您会做什么?给他们一个永久的“密钥”,这样他们就不必在每次使用应用程序时都登录了? 我强迫他们登录。要么使用cookie,要么将指纹映射到他们的UDID,但UDID意味着用户必须从同一设备访问服务。跨度> 关于第 3 步:这意味着如果我使用的 MVC 框架在“Controllers”中使用“Actions”,我应该在每个 Action 中添加两个额外的参数(指纹和 sessionid)?跨度> @sports 关于在方法调用的开头添加功能:如果您使用的是 MVC/WebApi,请使用 OWIN 拦截操作。如果您想允许通过 endoint 进行任何操作,但又想保护域逻辑,请使用 PostSharp 之类的 AOP。如果您自己滚动,只需使用属性并打破一系列原则,将功能放入您想要保护的方法的属性中。【参考方案3】:

3 年后编辑

我完全同意 Evert,将 OAuth2 与 HTTPS 一起使用,不要重新发明***! :-)

通过更简单的 REST API - 不适用于第 3 方客户端 - 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。

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

【讨论】:

这怎么不在Don't worry about being "RESTful", worry about security.答案之上? 太晚了,我不知道你在说什么,对不起。 :D 我明天会读这篇文章,我不记得了... 我设法再次阅读了这篇文章。是的,我认为这是因为与您提到的帖子相比,我的帖子延迟了 2 年。仅此而已,祝您有个愉快的夜晚! :-) 只是想了解更多。 3rd 客户端是什么意思? JWT 对他们来说有多不安全?谢谢。

以上是关于在不重新发明***的情况下保护 REST API的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有弹簧安全的情况下使用 api 密钥保护 rest api

如何在不维护 jsessionid 的情况下在 Spring Boot 中保护 RESTful API

在不使用 Azure SDK 的情况下使用 REST API 将流上传到 Azure Blob 存储

Easymock:如何在不可见的情况下模拟受保护方法的调用

如何在不经过注册用户身份验证的情况下保护公共API请求

有没有办法在不轮询 REST API 的情况下通知 Google AI Platform 训练作业的状态变化?