Ruby on Rails - 使用现有模式将 UUID 作为主键实现
Ruby on Rails - Implementing UUID as Primary Key With Existing Schema
目前我正在为移动应用程序创建 RESTful API。 RESTful API 有许多端点,允许用户在彼此之间交换个人信息。我正在测试这些端点的安全性,并很快意识到,如果第三方设法获得对 API 的访问权限,他们可以通过猜测他们的用户 ID 或使用自动脚本收集广泛的 API 来轻松查找其他用户的信息。 =51=]个人信息ge。这是因为我使用的主键是一个简单的自动递增整数,这使得确定其他用户的 ID 变得可预测且容易。我立即开始寻找不遵循明显模式的东西。我遇到了 UUID,并决定用我现有的 rails 应用程序来实现它们。
这是一个明智的决定吗?我肯定看到使用 UUID 的好处,但经过进一步研究,我发现这种方法有很多缺点。许多消息来源声称使用 UUID 会导致大型表出现性能问题。 UUID 适合我的情况吗?
我的第二个问题是关于在 Rails 应用程序上的现有 Ruby 中实现它。我按照这篇文章切换到 UUID:http://rny.io/rails/postgresql/2013/07/27/use-uuids-in-rails-4-with-postgresql.html。我 运行 遇到了启用 uuid-ossp
扩展的问题。我创建了一个迁移并将 enable_extension 'uuid-ossp'
放入更改函数中。然后我更改了现有的迁移以支持 UUID 作为它们的主键和 运行 rake db:drop db:create db:migrate
以使用编辑后的迁移重新创建数据库。失败并出现错误 PG::UndefinedFunction: ERROR: function uuid_generate_v4() does not exist
。我很快意识到这是因为在我编辑为使用 UUID 的迁移之后,我创建了启用 uuid-ossp
扩展的迁移。当我将迁移名称中的时间戳更改为所有迁移之前的日期时,db:migrate
命令完成且没有错误。这感觉很糟糕并且破坏了进行迁移的目的。通过迁移添加此扩展程序的正确方法是什么?
编辑回复评论:
所以有很多评论建议我应该在允许他们查看某些数据之前正确验证用户并检查他们的权限。我的应用程序内置了用户身份验证,但可以更好地解释我的情况以及为什么我需要的不仅仅是自动递增的主键。
我在这个应用程序上有很多用户,每个用户都可以创建私人和 public 联系人。 Public 每个使用移动应用程序的人都可以查看联系人。私人联系人只能由创建它们的用户查看。但是,用户可以通过向其他用户展示移动应用程序中编码有联系人 ID 的二维码,与其他用户共享他们的私人联系人。当用户解码联系人 ID 时,将向后端发送请求以通知后端用户现在是该私人联系人的所有者。这允许第二个用户现在接收来自该私人联系人的更新。这是我的应用程序的一大特点。这里的目的是迫使人们必须亲自交换这些联系人,并禁止其他人看到这些联系人,除非这个过程已经发生。
实施这个概念被证明是相当棘手的,因为所有用户都可能与系统上的任何其他用户共享所有私人联系人。我发现这非常难以使用权限来实现,因为用户可以查看的联系人不断变化。
最初我用自动递增的整数作为联系人 ID 的主键来实现它。它有效但迫使我创建一个非常不安全的 API 端点,该端点基本上将用户 ID 和私人联系人 ID 作为参数,并将该用户添加为该联系人的所有者。因为自动递增的 ID 是如此可预测,所以有权访问 API 的用户基本上可以每次循环调用端点的一系列数字,将序列号作为联系人 ID 传递,并将自己添加为联系人的所有者没有与他们分享。这将绕过必须亲自共享联系人的整个过程,并且在很大程度上破坏了拥有我的移动应用程序的目的。
我决定我需要一些不可预测的东西,完全 运行dom 并且每个私人联系人都是独一无二的。我在研究解决此问题时发现了 UUID,并将模型中的联系人 ID 更改为 UUID 类型。 UUID 是解决此问题的最佳方法吗?我应该用别的东西吗?我是否以错误的方式解决了这个问题?
Are UUIDs the best way to solve this?
您可以使用它们作为解决方案。如果这样做,您应该构建一个新的联系人 table 和模型,而不是尝试迁移旧模型。除了难以实施之外,任何迁移都会立即使现有的 contact/invite 电子邮件无效(因为它们包含旧 ID)。简要支持这两种模型,一旦您对使用它的流量对您的应用程序不再重要感到满意,就淘汰旧的自动递增 id 模型。
仍然存在一个缺陷 - 您的联系人共享 links 现在将是持久的,如果任何人出于任何原因访问联系人的 ID,并且知道足以构建 URL 获得该用户作为联系人,然后他们就可以将其共享给自己和完全不受您的应用程序控制的任何其他人。这是因为您依赖 id 的知识作为阻止访问联系方式的唯一因素。
Should I use something else?
在我看来,是的。使用单独的 nonce 或一次性代码模型(使用 UUID,或包含长随机字符串的索引列 - 您可以为此使用 SecureRandom
),可以授予权限完成分享。当有人想要共享联系人时,创建包含共享内容详细信息的 nonce 对象 - 例如contact_id
- 并使用它生成电子邮件 link 指向将找到随机数并允许访问资源的路由。
模型不需要称为 "Nonce" 或将其作为列包含,这只是模式的通用名称。相反,您可以调用新模型 "ContactShare" 和秘密 属性 "link_code".
这将允许您像往常一样使用应用的权限模型解决对联系人的访问,并阻止可能滥用共享 links。当调用具有 nonce id 或代码的控制器时,在此时创建权限以授予对联系人的访问权限。然后过期或删除随机数,这样它就不能被重新使用。我更喜欢过期时间,这样您就可以跟踪使用情况 - 这可以像 used
布尔列一样简单,您在共享请求成功后更新它。
注意我不是指的是Rack::Auth::Digest随机数例程,它特定于服务器身份验证。我没有找到 RoR 预建随机数模型,但它可能使用不同的名称。
目前我正在为移动应用程序创建 RESTful API。 RESTful API 有许多端点,允许用户在彼此之间交换个人信息。我正在测试这些端点的安全性,并很快意识到,如果第三方设法获得对 API 的访问权限,他们可以通过猜测他们的用户 ID 或使用自动脚本收集广泛的 API 来轻松查找其他用户的信息。 =51=]个人信息ge。这是因为我使用的主键是一个简单的自动递增整数,这使得确定其他用户的 ID 变得可预测且容易。我立即开始寻找不遵循明显模式的东西。我遇到了 UUID,并决定用我现有的 rails 应用程序来实现它们。
这是一个明智的决定吗?我肯定看到使用 UUID 的好处,但经过进一步研究,我发现这种方法有很多缺点。许多消息来源声称使用 UUID 会导致大型表出现性能问题。 UUID 适合我的情况吗?
我的第二个问题是关于在 Rails 应用程序上的现有 Ruby 中实现它。我按照这篇文章切换到 UUID:http://rny.io/rails/postgresql/2013/07/27/use-uuids-in-rails-4-with-postgresql.html。我 运行 遇到了启用 uuid-ossp
扩展的问题。我创建了一个迁移并将 enable_extension 'uuid-ossp'
放入更改函数中。然后我更改了现有的迁移以支持 UUID 作为它们的主键和 运行 rake db:drop db:create db:migrate
以使用编辑后的迁移重新创建数据库。失败并出现错误 PG::UndefinedFunction: ERROR: function uuid_generate_v4() does not exist
。我很快意识到这是因为在我编辑为使用 UUID 的迁移之后,我创建了启用 uuid-ossp
扩展的迁移。当我将迁移名称中的时间戳更改为所有迁移之前的日期时,db:migrate
命令完成且没有错误。这感觉很糟糕并且破坏了进行迁移的目的。通过迁移添加此扩展程序的正确方法是什么?
编辑回复评论:
所以有很多评论建议我应该在允许他们查看某些数据之前正确验证用户并检查他们的权限。我的应用程序内置了用户身份验证,但可以更好地解释我的情况以及为什么我需要的不仅仅是自动递增的主键。
我在这个应用程序上有很多用户,每个用户都可以创建私人和 public 联系人。 Public 每个使用移动应用程序的人都可以查看联系人。私人联系人只能由创建它们的用户查看。但是,用户可以通过向其他用户展示移动应用程序中编码有联系人 ID 的二维码,与其他用户共享他们的私人联系人。当用户解码联系人 ID 时,将向后端发送请求以通知后端用户现在是该私人联系人的所有者。这允许第二个用户现在接收来自该私人联系人的更新。这是我的应用程序的一大特点。这里的目的是迫使人们必须亲自交换这些联系人,并禁止其他人看到这些联系人,除非这个过程已经发生。
实施这个概念被证明是相当棘手的,因为所有用户都可能与系统上的任何其他用户共享所有私人联系人。我发现这非常难以使用权限来实现,因为用户可以查看的联系人不断变化。
最初我用自动递增的整数作为联系人 ID 的主键来实现它。它有效但迫使我创建一个非常不安全的 API 端点,该端点基本上将用户 ID 和私人联系人 ID 作为参数,并将该用户添加为该联系人的所有者。因为自动递增的 ID 是如此可预测,所以有权访问 API 的用户基本上可以每次循环调用端点的一系列数字,将序列号作为联系人 ID 传递,并将自己添加为联系人的所有者没有与他们分享。这将绕过必须亲自共享联系人的整个过程,并且在很大程度上破坏了拥有我的移动应用程序的目的。
我决定我需要一些不可预测的东西,完全 运行dom 并且每个私人联系人都是独一无二的。我在研究解决此问题时发现了 UUID,并将模型中的联系人 ID 更改为 UUID 类型。 UUID 是解决此问题的最佳方法吗?我应该用别的东西吗?我是否以错误的方式解决了这个问题?
Are UUIDs the best way to solve this?
您可以使用它们作为解决方案。如果这样做,您应该构建一个新的联系人 table 和模型,而不是尝试迁移旧模型。除了难以实施之外,任何迁移都会立即使现有的 contact/invite 电子邮件无效(因为它们包含旧 ID)。简要支持这两种模型,一旦您对使用它的流量对您的应用程序不再重要感到满意,就淘汰旧的自动递增 id 模型。
仍然存在一个缺陷 - 您的联系人共享 links 现在将是持久的,如果任何人出于任何原因访问联系人的 ID,并且知道足以构建 URL 获得该用户作为联系人,然后他们就可以将其共享给自己和完全不受您的应用程序控制的任何其他人。这是因为您依赖 id 的知识作为阻止访问联系方式的唯一因素。
Should I use something else?
在我看来,是的。使用单独的 nonce 或一次性代码模型(使用 UUID,或包含长随机字符串的索引列 - 您可以为此使用 SecureRandom
),可以授予权限完成分享。当有人想要共享联系人时,创建包含共享内容详细信息的 nonce 对象 - 例如contact_id
- 并使用它生成电子邮件 link 指向将找到随机数并允许访问资源的路由。
模型不需要称为 "Nonce" 或将其作为列包含,这只是模式的通用名称。相反,您可以调用新模型 "ContactShare" 和秘密 属性 "link_code".
这将允许您像往常一样使用应用的权限模型解决对联系人的访问,并阻止可能滥用共享 links。当调用具有 nonce id 或代码的控制器时,在此时创建权限以授予对联系人的访问权限。然后过期或删除随机数,这样它就不能被重新使用。我更喜欢过期时间,这样您就可以跟踪使用情况 - 这可以像 used
布尔列一样简单,您在共享请求成功后更新它。
注意我不是指的是Rack::Auth::Digest随机数例程,它特定于服务器身份验证。我没有找到 RoR 预建随机数模型,但它可能使用不同的名称。