暴露数据库 ID ——安全风险?

我听说公开数据库 ID (例如,在 URL 中)是一种安全风险,但是我很难理解为什么。

对于为什么有风险或者为什么没有风险有什么看法或者链接吗?

编辑: 当然访问是有作用域的,例如,如果你看不到资源 foo?id=123,你将会看到一个错误页面。否则 URL 本身应该是秘密的。

编辑: 如果 URL 是保密的,它可能包含一个生成的令牌,生存期有限,例如,有效期为1小时,只能使用一次。

编辑(几个月之后) : 我目前的首选做法是对 ID 使用 UUIDS 并公开它们。如果我使用序列号(通常用于某些 DBs 上的性能)作为 ID,我喜欢为每个条目生成一个 UUID 令牌作为备用键,并公开它。

53719 次浏览

如果在数据库中使用整数 ID,可以通过更改 qs 变量使用户更容易看到他们不应该看到的数据。

例如,用户可以很容易地改变这个 qs 中的 id 参数,并查看/修改他们不应该 http://someurl?id=1的数据

一般的想法是这样的: “向任何人透露一点关于你的应用程序内部工作原理的信息。”

公开数据库 ID 算是公开某些信息。

原因是黑客可以使用任何关于你的应用程序内部工作原理的信息来攻击你,或者用户可以改变 URL 进入一个他/她不应该看到的数据库?

这取决于身份证代表什么。

考虑一个网站,由于竞争的原因,不想公开他们有多少成员,但通过使用顺序 ID 显示它无论如何在 URL: http://some.domain.name/user?id=3933

另一方面,如果他们使用用户的登录名: http://some.domain.name/user?id=some,他们没有披露任何用户不知道的信息。

当您发送数据库 ID 到您的客户端时,您是 被迫的来检查两种情况下的安全性。如果你在你的 web 会话中保留 id,你可以选择是否需要这样做,这意味着可能更少的处理。

您总是试图将事情委托给访问控制;)这个 在您的应用程序中是这种情况,但是我在整个职业生涯中从未见过如此一致的后端系统。其中大多数安全模型是为非网络使用而设计的,有些是在死后添加的额外角色,而有些则被固定在核心安全模型之外(因为角色是在不同的操作环境中添加的,比如说在网络之前)。

因此,我们使用合成会话本地 ID,因为它隐藏了我们能够避免的最多信息。

还有非整数键字段的问题,枚举值和类似的字段可能就是这种情况。您可以尝试清除这些数据,但最终的结果可能会像 小 Bobby 桌子一样。

公开数据库标识符存在相关风险。另一方面,设计一个 Web 应用程序而不公开它们将是极其麻烦的。因此,了解风险并小心处理它们是非常重要的。

第一个危险是 OWASP 所称的 “不安全的直接对象引用”如果有人发现了一个实体的 id,并且您的应用程序缺乏足够的授权控制来防止它,那么他们可以做一些您不想做的事情。

以下是一些可以遵循的好规则:

  1. 使用基于角色的安全性来控制对操作的访问。实现方式取决于您选择的平台和框架,但是许多支持声明性安全模型,当某个操作需要某种权限时,该模型会自动将浏览器重定向到身份验证步骤。
  2. 使用编程安全性控制对对象的访问。这在框架级别上比较难做到。更常见的情况是,这是您必须写入代码的内容,因此更容易出错。这种检查不仅仅是基于角色的检查,它不仅确保用户拥有操作的权限,而且还对正在修改的特定对象拥有必要的权限。在基于角色的系统中,很容易检查只有经理才能加薪,但除此之外,还需要确保员工属于特定经理的部门。

有一些方案可以对最终用户隐藏真正的标识符(例如,在真正的标识符和服务器上的临时的、用户特定的标识符之间进行映射) ,但是我认为这是一种隐藏的安全形式。我希望专注于保持真正的加密机密,而不是试图隐藏应用程序数据。在 Web 上下文中,它还与广泛使用的 REST 设计背道而驰,在 REST 设计中,标识符通常显示在 URL 中,用于寻址受访问控制的资源。

另一个挑战是预测或发现标识符。攻击者发现未授权对象的最简单方法是从编号序列猜测对象。下列准则有助于减轻这种情况:

  1. 只公开不可预测的标识符。为了提高性能,您可能会在数据库内的外键关系中使用序列号,但是您希望从 Web 应用程序引用的任何实体也应该具有不可预测的代理标识符。这是唯一一个应该暴露给客户的。对这些代理密钥使用随机 UUID 是分配这些代理密钥的实用解决方案,尽管它们在加密上并不安全。

  2. 但是,在会话 ID 或其他身份验证令牌中需要加密不可预测的标识符,其中 ID 本身对请求进行身份验证。这些应该由加密 RNG 生成。

我们使用 GUID 作为数据库 ID,泄露它们的危险性要小得多。

虽然不是 资料保安风险,但绝对是 商业情报保安风险,因为它暴露了数据大小和速度。我已经看到企业因此受到损害,并且深入地写过关于这种反模式的文章。除非你只是在做实验,而不是做生意,否则我强烈建议你不要公开你的私人身份。https://medium.com/lightrail/prevent-business-intelligence-leaks-by-using-uuids-instead-of-database-ids-on-urls-and-in-apis-17f15669fd2e

从代码设计的角度来看,应该将数据库 ID 视为持久化技术的私有实现细节,以跟踪行。如果可能的话,您应该在设计应用程序时绝对不要以任何方式引用此 ID。相反,您应该考虑一般情况下如何标识实体。一个人的身份是否与他的社会安全号码一致?一个人是否与他们的电子邮件一致?如果是这样,那么您的帐户模型应该只有对这些属性的引用。如果没有真正的方法来识别具有这样一个字段的用户,那么您应该在命中数据库之前生成一个 UUID。

这样做有很多好处,因为它允许您将领域模型与持久化技术分离开来。这意味着您可以替换数据库技术,而不必担心主键兼容性。如果编写了适当的授权代码,那么将主密钥泄漏到数据模型并不一定是一个安全问题,但它表明代码设计不够优化。

我的建议是实施两个阶段的安全。

  1. “隐晦式安全” : 可以在表中使用整数 Id 作为主键,使用 Gid 作为 GUID 作为代理键。整数 Id 列用于关系和其他数据库后端和内部用途(甚至用于 Web 应用中的选择列表键,以避免在加载和保存时 Gid 和 Id 之间不必要的映射) ,而 Gid 用于 REST Urls,即用于 GET、 POST、 PUT 和 DELETE 等。因此,一个不能猜测其他记录 ID。这为防止基于猜测的攻击提供了第一级保护。(即数列猜测)

  2. 服务器端的基于访问的控制 : 这是最重要的,您可以通过各种方式根据应用程序中定义的角色和权限来验证请求。决定权在你。