在数据库表中有两个唯一ID的坏主意?

时间:2009-06-04 08:07:27

标签: php mysql

我希望允许用户通过关注URL查看我的数据库中的记录。

我猜这个URL不是一个好主意,其中要查看的记录的标识符是记录自动增量ID!

http://www.example.com/$db_record_id

以上是不必要地提供信息。这是真的吗?不会为每一行创建自己的ID会造成同样的问题吗?

有没有更好的方法来解决我的问题。

环境:LAMP(PHP)

全部谢谢

12 个答案:

答案 0 :(得分:3)

您要发出两条信息:

  • 易于预测的记录网址
  • 很容易找出总共有多少记录

这些事情对您的应用程序是一个问题,然后使用其他东西

您可以将GUID用于Db密钥,但这可能会对大型数据集产生潜在的性能影响。

答案 1 :(得分:3)

将记录的ID放在URL中通常不是问题。例如,查看此浏览器窗口的URL,您将看到此问题的ID。

如果由于某种原因不希望ID清晰可见,您可以对值进行加密或加密。如果您需要保护某些记录不被查看,这当然不是一种安全的方法,那么您必须将其与某种身份验证相结合,例如登录用户的会话ID。

编辑:
为了保证适当的安全性,必须关注真正的问题。如果某些页面应该限制访问,问题不是任何人都可以找到页面的URL,问题是任何人都可以查看该页面。 URL总是可以通过某种方式获得(例如包嗅探),因此必须以其他方式实现安全性。

答案 2 :(得分:2)

您提供的信息太少,无法提供真正有用的答案。

  • 如何生成网址?
  • 软件如何找到要显示的记录?

那就是说,我同意公开这样的ID是有问题的。 commmon解决方案是每次向数据库查询一组记录时生成临时ID,并在内部存储tempID->真实ID。然后将这些临时ID放入URL中,并在服务器上进行翻译。

答案 3 :(得分:2)

该方法的一个可能问题是,通过顺序递增URL中的ID,人们很容易检索所有页面/记录。这可能不是您想要的,但是您不应该依赖于使用模糊的URL来保证安全。

其他一些选择是:

  • 在每一行上生成一个随机哈希(虽然这将是一个讨厌的无意义的网址)
  • 为每一行生成一个'slug'(例如'bad-idea-to-two-unique-id-in')。您需要明确确保这是唯一的,例如通过添加其他内容。

答案 4 :(得分:2)

如果我是你,我会在你的桌子上使用整数主键(自动识别码) 并添加一个具有唯一约束的GUID&索引,默认为UUID()

然后装备您的页面以获取URL上的GUID并使用它来搜索您的表。

答案 5 :(得分:1)

也许您应该公开另一个唯一标识符,例如标题而不是主键?公开您的PK不一定会带来安全风险,但如果您可以公开其他属性,您可能会在搜索结果上获得更高的优势。

答案 6 :(得分:1)

用户请求中的主键本身不容易受到攻击。只需将其转换为整数值即可。

$id = (int)$id;

另一个问题是限制某些记录的访问。您可以通过简单编辑查询来解决此问题,并添加一些访问规则。例如,如果您有admin / editor / reader / guest类型的用户,则可以在SET字段中保存访问权限并将条件添加到查询中

SELECT ... 
FROM mytable 
WHERE 
    id = (int)$id 
    AND 
    (FIND_IN_SET('admin', access) OR FIND_IN_SET('editor', access))

...
if (!$fetch = mysql_fetch_acssoc($res))
    throw new Exception('Record not found or you have no permission to access it');

所以,不要担心主键 - 如果你不忘记将它们转换为整数以避免SQL注入,它们是非常安全的。

答案 7 :(得分:0)

这不是一个好主意,因为它已经被说过了(你实际上暴露了表中的每一行),我认为没有必要。

我认为用户将在某个场景(从列表中选择元素或其他内容)后到达该页面,因此您将有一个页面提交和一个控制器(如果您尝试使用MVC架构)将处理所需的任何处理,它将发送到一个查看页面,该页面可能只是一个www.yoursite.com/displayElement.htm

通过这种方式,ID只是作为会话变量传递,不会显示在任何地方。

但是如果我弄错了并且你正在显示某种目录,那么你希望用户能够为页面添加书签,而不是只需要添加一些混淆机制来创建基于ID的复杂字符串,在将ID发送到URL并在代码中解码之前对ID进行编码以获得实际ID。

答案 8 :(得分:0)

如果用户无论如何都可以观看该页面,我发现使用该ID没有问题。如果他们想要改变网址并转到随机页面,我会毫无疑问。

如果不让任何人看到这些页面,我实际上仍然没有问题。因为如果是这种情况,你应该进行一些授权检查,这会阻止他们看到他们不被允许看到的页面。

答案 9 :(得分:0)

您所描述的是称为直接对象引用的漏洞。这些本质上并不是坏事,但是Insecure Direct Object References在OWASP前十名中是#4。

您可以通过检查属于当前用户的对象来保护直接对象引用,如果不存在则不显示它。

此外,即使是拒绝访问的消息也可能会泄露信息。例如,如果您的参数是一个订单号,攻击者可以发现您的公司实际拥有的订单数量,即使您没有显示它们只需增加数量直到获得404。

我个人只是使​​用GUID作为间接对象引用的一种形式,但显然不是数据库中的主键。

答案 10 :(得分:0)

威胁级别取决于范围和受众:

  1. 这是一个内部的crud应用程序吗?如果是这样,您可能不需要担心它。
  2. 这是公开的信息(如推特帖子)吗?同样,您可能不需要担心它。实际上,可预测的URL可能是链接的理想选择。
  3. 您的身份验证用户可以修改任何记录或查看他们不应该的内容吗?您可以通过实施所有权系统来降低此风险。
  4. 是否会导致1次点击操作或XSS漏洞?如果可以的话,你做错了。
  5. 一般来说,我赞成可预测的URL。话虽如此,重要的是要考虑如何使用它们以及谁可以看到它们。

答案 11 :(得分:0)

如果你想确保人们不只是猜测URL,那么这是一个简单的方法。这绝不是安全(即不要使用此方法进行访问检查),但它将确保您不能只输入随机URL并将sendt发送到该页面。< / p>

使用网址中的另一条信息补充ID。我建议使用id的盐渍哈希。

生成网址时:

$id = 5;
$hash = md5($id . "MY_SALT_VALUE");
$url = "/$id/$hash";

显示记录时:

$params = explode(',', $_SERVER['REQUEST_URL']);
$id = $params[0];
$hash = $params[1];
if($hash != md5($id ."MY_SALT_VALUE")) {
    die('Uh oh! You guessed the URL, didn\'t you! Bad user!');
}
$data = $MyModel->load($id);
if(!$data) {
    die('No such record');
}
DisplayModel($data);

当然,这是一个模型(在错误消息中说太多,只是die()而不是正确的404页面,依此类推。)