【问题标题】:Is it a bad practice to expose the database ID to the client in your REST API?在 REST API 中向客户端公开数据库 ID 是一种不好的做法吗?
【发布时间】:2019-10-27 20:10:31
【问题描述】:

在我的职业生涯中,我曾多次讨论过这个问题。在我看来,在您的 REST API 响应中将存储在数据库中的 id 公开给客户端是完全可以的。但与我共事过的一些人认为这确实是安全方面的第一课:“永远不要将数据库 ID 暴露给客户端。”

然后它们会带来各种复杂性来避免这种情况。例如,在一项工作中,我必须对我的休息响应中的每个 ID 进行哈希处理,然后对请求中的所有 ID 进行取消哈希处理。

现在在我的新工作中,我们有以下模式。一个表有一个自动递增的“id”,但我们不公开它,在它旁边我们有一个 uuid“代码”,这就是我们向客户端公开的那个。所以本质上我们有 2 个 id,都存储在数据库中,但一个我们可以公开,另一个我们可以,因为:

“永远不要将您的数据库 ID 暴露给客户端。”

这有点道理吗?我们仍然向客户端公开一个“标识符”。如果问题是有人可以看到我们在一个表中有多少行,因为“id”是自动递增的,我只会将“id”设为 uuid,并将其公开给客户端。

如果您查看其他公共休息 API 的示例,在我看来,它们总是公开数据库 ID,没有问题。比如gitlab:

GET /projects/:id/users

[
  {
    "id": 1,
    "username": "john_smith",
    "name": "John Smith",
    "state": "active",
    "avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg",
    "web_url": "http://localhost:3000/john_smith"
  },
  {
    "id": 2,
    "username": "jack_smith",
    "name": "Jack Smith",
    "state": "blocked",
    "avatar_url": "http://gravatar.com/../e32131cd8.jpeg",
    "web_url": "http://localhost:3000/jack_smith"
  }
]

推特: https://api.twitter.com/1.1/statuses/show.json?id={id}

但即使是stackoverflow: https://stackoverflow.com/questions/{id} https://stackoverflow.com/users/{id}

我敢打赌,网址 https://stackoverflow.com/users/2188707 中的 2188707 只是我在 stackoverflow 数据库中的用户 ID。

【问题讨论】:

    标签: rest security


    【解决方案1】:

    我没有看到任何安全原因在您的 API 中公开纯数据库 ID。 如果您的数据库暴露在外,您无论如何都会丢失。通过默默无闻的安全永远不是解决方案。

    但是,还有一些其他原因需要考虑:

    • 公开数据库 ID 会创建与数据库的耦合。想象一下合并来自不同数据库的数据(共享相同的模式),或者将备份数据应用到已经在使用的数据库中。无法保证相同的 ID 仍然可用。

    • 设计一个适当的基于资源的 API 要求您公开通用唯一 ID (UUID) 或技术复合键,原因很简单,因为没有其他方法可以确保跨不同系统/数据库的唯一性。

    【讨论】:

    • 那么,如果您的应用程序中存在 SQL 注入漏洞怎么办?拥有内部 ID 可能会使情况变得更糟。此外,它还可以通过良好的分析来重建数据结构。
    • 根据我的经验,只要您对 SQL 注入持开放态度,您几乎可以迭代整个数据库。您是否有一个实际上仅在具有可用 ID 时才有效的示例?接下来我想强调的是,我反对在 REST API 中使用 db 标识符。只是出于不同的原因。
    • 目前没有,但我相信这是可能的。我的观点是 id 可能会使情况变得更糟,因为 id 可以允许推断 FK 并帮助关联 API 操作之间的数据。
    • 如果你提供一个多租户服务,在租户之间共享表(区分列),并且路径中的ID是表的主键,因此它与数量成比例增加或在该表的行中,您正在向不应该知道这一点的客户公开有关该业务增长的信息。是的,当然经常谁在乎……但你必须知道你违反了信息隐藏并决定它是否可以接受。
    【解决方案2】:

    不是安全问题,但它让用户了解有关您作为公司的数据大小的一些信息。而有些公司不喜欢公开这类信息

    【讨论】:

    • 如果您使用数据库管理的 ID 序列,通常会为单个客户端保留块。所以在这些情况下,ID 实际上可能比实际数据量大得多。但除此之外,我完全同意你的观点
    【解决方案3】:

    通过在API用户中公开id,如果有人可以创建一个新用户,然后调用你的用户API,他可以自动知道你的数据库中有多少用户,而在许多业务中,这不是那种您希望您的同意知道的信息。

    【讨论】:

      【解决方案4】:

      顺序主键存在一些问题:

      1. 它们显示您的数量(例如:如果您创建一个对象并且 API 返回 ID 10,001,它会粗略估计您的数据库中有多少此类对象,这可能对黑客或竞争)
      2. 黑客可以利用“不安全的直接对象引用”(link)
      3. 黑客可以利用它进行 XSS 攻击 (link)

      来源:改编自 Django 1.11 的两勺

      【讨论】:

        【解决方案5】:

        这个问题很老了,但现在可以回答,以防答案对新人有用。

        '我只需将“id”设为 uuid,并将其公开给客户端。'。

        使用 uuid 隐藏数字 id 并暴露其他 id 的原因是因为数据库系统在 uuid 字段的索引方面性能不佳,而且具有 uuid 类型的外键也会增加存储空间,这当然取决于 uuid 版本和索引类型。 出于这个原因,许多系统在主键中设置了自动增量数字,但在公开信息中隐藏了它,与 uuid 字段具有相同的防止公开。

        【讨论】:

          猜你喜欢
          • 2012-04-11
          • 1970-01-01
          • 1970-01-01
          • 2020-09-08
          • 1970-01-01
          • 2017-12-16
          • 2020-11-28
          • 1970-01-01
          • 2023-03-24
          相关资源
          最近更新 更多