假设我们有两个这样的模型:
User:
_ _id
- name
- email
Company:
- _id
_ name
_ slug
Run Code Online (Sandbox Code Playgroud)
现在让我们说我需要将用户连接到公司.用户可以分配一个公司.为此,我可以添加companyID在用户模型中调用的新字段.但我不是把_id球场送到前端.所有来到API的请求都将是slug唯一的.我有两种方法可以做到这一点:
1)添加slug以关联公司:如果我这样做,我可以从请求发送的slug并直接查询公司.
2)添加_id公司:如果我这样做,我需要首先使用slug查询公司,然后使用_id返回查询所需的数据.
我可以知道哪种方式最好吗?使用_id关系记录时是否有额外的好处?
同意第二种方法。在决定使用哪个字段作为连接键时需要考虑几个问题(所有数据库都是如此,而不仅仅是 Mongo):
由于这些原因,几乎总是建议使用仅用作关键字段的关键字段,其中不存储任何实际信息。很多人都因为使用社会安全号码、驾驶执照等作为关键字段而被烧伤,这要么是因为可能存在重复(例如,如果人们使用假号码,或者如果他们没有号码,SSN 可能会重复) ,或者数字可能会改变(例如驾驶执照)。
另外,通过这样做,您可以格式化关键字段以优化唯一生成和索引的速度。例如,如果您使用 SSN,则需要根据数据库的其余部分检查 SSN 以确保其唯一。如果您有数百万条记录,这需要时间。对于 slugs 也是如此,它们是需要进行哈希处理并根据索引进行检查的文本字段。OTOH,mongoDB 本质上使用 UUID 作为键,这意味着它不必检查唯一性(该算法保证唯一性的高统计可能性)。
最重要的是,如果可以的话,有充分的理由不使用“真实”字段作为密钥。幸运的是,mongoDB 已经为您提供了一个满足上述所有条件的重要字段,即 _id 字段。因此,您应该使用它。即使 slug 不是一个“真正的”字段,并且您生成它的方式与 _id 字段完全相同,为什么还要麻烦呢?为什么一条记录必须有 2 个唯一标识符?
您的情况的第二个问题是您没有向用户公开公司的 _id 字段。直觉上,这似乎应该是一条有价值的信息,不应该随意泄露。但事实是,它本身没有信息价值,因为如上所述,密钥不应该有实际信息。实现安全性的地方是在查询中,确保执行查询的用户有权访问她所请求的记录/特定字段。隐藏密钥是一种经典的隐藏式安全方法,实际上并不能提高安全性。
隐藏主键的唯一时机是,如果您使用的键未经深思熟虑,但确实包含有用信息。例如,某人可以使用每张发票加 1 的发票 ID 来计算您一天收到的订单数量。自动增量 ID 也很容易被猜到(如果我的发票是 #5,我可以窥探发票 #6 吗?)。幸运的是,Mongo 使用 UUID,因此实际上不会泄露任何信息(除了对其加密算法的定时攻击?如果您担心这一点,那么您需要比这篇文章更深入的安全考虑:-)。
从另一个角度来看:如果 slug 可靠地指向特定公司和用户,那么它如何比仅使用 _id 更安全?
也就是说,在某些情况下,公开辅助密钥(如 slugs)是有帮助的,但这些都与安全性无关。例如,如果将来您需要迁移数据库平台并需要重新生成密钥,因为新平台无法使用您的旧平台;或者,如果用户将手动输入标识符,那么为他们提供一些更容易记住的东西(例如slugs)会很有帮助。但即使在这些情况下,您也可以使用 slug 作为方便用户使用的标识符,但在您的数据库中,您仍然应该使用公司 ID 来执行实际的连接(如选项#2 中所示)。查看有关向用户公开 _ids 的优点/缺点的讨论: https://softwareengineering.stackexchange.com/questions/218306/why-not-expose-a-primary-key
因此,我的建议是继续为用户提供公司 ID(如果您想要人类可读的格式(例如 URL,尽管 mongo _ids 可以在 URL 中使用),则还需要提供 slug)。他们可以将其发送回给您以获取用户,并且您可以(在适当的权限检查后)进行加入并发送回用户数据。如果您不想公开公司 ID,那么我建议您使用选项#2,这本质上是相同的,只是您要添加一个额外的查询来首先获取公司 ID。恕我直言,这浪费了周期,没有真正提高安全性,但如果有其他考虑,那么它仍然是可以接受的。这两个选项都比使用 slug 作为主键更好。
| 归档时间: |
|
| 查看次数: |
145 次 |
| 最近记录: |