0

我正在创建一个用户可以登录或注册的项目,但我刚刚发现了一个安全漏洞。

首先让我讲一下用户从服务器收到令牌时的流程,

用户可以注册或登录,如果所有验证都正确,则服务器将响应:

{
  "meta": {
    "issueDate": 1592078419167,
    "expToken": "10800000"
  },
  "payload": {
    "user": {
      "id": 3,
      "email": "new3@gmail.com",
      "username": "new3"
    },
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MywiZW1haWwiOiJuZXczQGdtYWlsLmNvbSIsInVzZXJuYW1lIjoibmV3MyIsImlhdCI6MTU5MjA3ODQxOSwiZXhwIjoxNTkyMDg5MjE5fQ.cjLgQjc2QbIhgumG2X2VsLk70c58F7NrKboYL2F2Sa0"
  }
}

Authorization: 'bearer TOKEN'然后使用该令牌,他可以通过将其作为模式附加到标头中来执行 CRUD 操作。使用令牌后,服务器中的中间件会检查它是否被篡改或过期(我在这里使用 JWT),如果它已过期或被篡改,那么服务器会使用401 unauthorized.

我注意到的是这个。可以说我有桌子USERSPOSTS(1:N)。User1 有 2 个 id 分别为 1 和 2 的帖子,然后另一个用户注册,我们称他为 User2,User2 注册成功收到一个令牌然后转到终端使用 curl,发送一个api/post/1/edit他不拥有的路由请求。这是我的问题。了解互联网/API 工作原理的用户可以获取令牌并访问任何资源。

我想到的解决方案很少。

  1. 创建一个中间件,通过查询数据库来检查用户是否拥有资源。但我不认为这是一个高性能的解决方案,因为我必须在不同的控制器上查询并执行它,比如 users_controller、posts_controller、another_controller。

  2. 我将使用 UUID 而不是递增 ID,因此每当他们尝试访问帖子编辑路线时,他们都无法轻松找出 ID。像api/post/1akA13124S5129/edit<--- 这很难弄清楚。

PS:我在Facebook上试过,但它不起作用。我认为他们有很多令牌和cookies。顺便说一句,我现在不会在任何请求中使用/包含任何 cookie。

4

2 回答 2

1

您设计了两种常见的解决方案。第一种是最简单也是最常见的。您正在处理多少个请求/秒,您会遇到性能问题?在您构建更复杂的解决方案之前,我会首先考虑优化您的数据库查询。

但在某些情况下,第二种解决方案(“稀疏”标识符)非常方便。我一直在使用它们。唯一重要的是,这意味着知道标识符意味着访问。因此,您可能无法拥有像api/post/1akA13124S5129/edit. “阅读,但不要编辑”的 URL 会是什么样子?它不能包含“1akA13124S5129”,因为知道该标识符的任何人都可以通过添加来编辑帖子/edit

我最喜欢使用“知道标识符授予访问权限”的方法是使用数据的 SHA-256 哈希作为标识符。这意味着为了猜测标识符,您需要已经知道内容。这是处理图像之类的非常好的方法。但它不适用于你想要编辑的东西,就像你在这里做的那样。

如果你真的不能进行数据库查找(如果不能,你真的应该扩展这个问题来解释你的问题),那么还有很多其他方法,但它们在很大程度上取决于你的精确要求。例如:

  • 如果用户可以编辑自己的帖子,但任何人都可以阅读任何帖子,则让 URL 定义权限。例如:api/post/alice/1只能由 alice 编辑。
  • 不仅将 JWT 用于身份验证 (authC),还可以将其用于授权 (authZ)。例如,当您要访问时api/post/1/edit,首先您必须连接到 authZ 服务器并请求 JWT。该服务器将进行数据库查找,然后授予您专门针对该 URL 的 JWT(或者您可以批量处理一组 URL,或像“管理员”这样的权限组)。然后您可以多次重用该 JWT,并且系统的资源服务端不必重新验证您的访问权限。它可以依赖 JWT 直到过期。这可以减轻数据库的大量负载。

但除非您的系统非常大,并且您已经尽一切努力优化数据库查询,否则我只会查询数据库。这就是他们的目的。

于 2020-06-18T22:43:30.917 回答
1

绝对是第一。这就是 Facebook、StackExchange、Google、Microsoft 和大多数流行网站用于保护其 API 的方法。

我将使用 UUID,所以每当他们尝试访问帖子编辑路线时

他们最初是什么时候获得这些 UUID 的?您实际上是为每个资源生成一个令牌。这样,当用户只是想查看今天的帖子时,您的后端仍将最终查询数据库以生成/选择每个帖子的 UUID,即使用户不太可能更新他们正在查看的每个帖子. 哦,你想延迟 UUID 直到用户真正调用编辑路由?由于用户仍然需要首先获取该 UUID,因此它只是一个额外的“将 UUID 传递给用户”步骤,不会增加任何安全性。

如果资源不是完全保密的并且只能供一个用户使用,那么这也将成为一个令人头疼的问题。在 Facebook 上,个人帖子只能由提交者删除/编辑,但其他人可以对其发表评论或做出反应。由于 Facebook 需要跟踪谁对什么做出了反应,因此他们最终仍会检查身份验证令牌并与用户表相关联。同时,您的 UUID 方法最终会为每个不同的用户创建多个 UUID,因此如果说一个帖子被数百个用户看到,那么您最终会为该帖子存储数百个 UUID。然后考虑评论(可以被评论者删除,并且帖子创建者),页面/组帖子(可以由页面/组管理员删除),甚至这个网站,任何人都可以编辑问题和答案。

于 2020-06-18T05:57:44.453 回答