在GET参数(PHP)中隐藏自动增量ID

时间:2009-09-15 11:19:50

标签: php security encryption parameters get

  

编辑:我发现并发布了一个高效优雅的解决方案,可将3141592等ID转换为vJST等字符串,然后向后转换。它可用于PHP:

     

https://github.com/delight-im/PHP-IDs

     

提供一些背景知识,它使用Knuth的乘法散列,然后进行基本转换,以生成唯一的,可逆的,非顺序ID。

问题:

我在PHP中有动态页面,其中的内容根据给定的ID显示。 id始终通过GET参数提交:page.php?id = X这会导致问题:站点访问者可以枚举id并简单地遍历所有不同的内容页面。当然,这是不可能的。

如何解决这个问题?

我的方法是对链接和表单中的所有ID进行编码,以后将其用作GET参数。在每个页面的开头,给定的id被解码为在数据库中使用的“真实”id。这是一个好方法吗?你会选择另一种方式吗?

我的方法的可能解决方案:

我会将整数id转换为基数为38的整数,并将数字替换为给定列表的字符。我会将这些字符用于编码的字符串id:

a-z 0-9 - _

你也会使用其他角色吗?对于这些字符,我的脚本将是:

function id2secure($old_number) {
    $alphabet_en = array(0=>'1', 1=>'3', 2=>'5', 3=>'7', 4=>'9', 5=>'0', 6=>'2', 7=>'4', 8=>'6', 9=>'8', 10=>'a', 11=>'c', 12=>'e', 13=>'g', 14=>'i', 15=>'k', 16=>'m', 17=>'o', 18=>'q', 19=>'s', 20=>'u', 21=>'w', 22=>'y', 23=>'b', 24=>'d', 25=>'f', 26=>'h', 27=>'j', 28=>'l', 29=>'n', 30=>'p', 31=>'r', 32=>'t', 33=>'v', 34=>'x', 35=>'z', 36=>'-', 37=>'_');
    $new_number = '';
    while ($old_number > 0) {
        $rest = $old_number%38;
        if (!isset($alphabet_en[$rest])) { return FALSE; }
        $new_number .= $alphabet_en[$rest];
        $old_number = floor($old_number/38);
    }
    $new_number = strrev($new_number);
    return $new_number;
}

其他问题:

我的功能的反向功能是什么?

我希望你能帮助我。谢谢!

6 个答案:

答案 0 :(得分:8)

用户可以通过网站访问这些页面吗?如果答案是肯定的,那么你应该问问自己这是否真的是一个问题。

如果没有,那么问题在于你没有保护你的网页或换一种方式:你依靠默默无闻的安全,这绝不是一个好的举动。

我的建议?保护您的网页,以便只有合适的用户才能访问它们,或者不用担心它。

如果你真的必须担心它,只需传递一个对于给定页面必须正确的额外字段。我不会从ID构造这个。在数据库中创建页面条目时,可能会生成另一个数字或GUID。如果两个字段都不正确,则不要显示该页面。

忘记简单的字符替换和其他天真的混淆技术。他们浪费你的时间。

编辑:如果您使用的是相同长度的非顺序ID,请考虑使用UUID而不是自动增加主键。基本上这是在应用程序级别完成的:

  • 将主键更改为char(36);
  • 在insert语句中,您必须设置密钥并使用MySQL UUID()函数填充它。

查看To UUID or not to UUID ?UUID as a primary key。由此导致性能下降(特别是因为您使用字符而不是整数进行查找)但除非您有大量(100万行)或数据,否则它在实践中可能不会成为问题。

答案 1 :(得分:1)

使用checksum algorithm like Luhn

$id = 1337;

$_GET['id'] = Luhn($id, 3); // 1337518, adds 3 checkdigits
$_GET['id'] = Luhn_Verify($_GET['id'], 3); // 1337, returns the original number of false if validation fails

echo $_GET['id']; // 1337
编辑:我忘了提及,但是通过使用这种方法,您可以检查ID是否有效,甚至不必查询数据库,例如:

$id = Luhn_Verify($_GET['id'], 3);

if ($id === false)
{
    // someone is trying to guess the ID
}

else
{
    // $id is valid, do the DB stuff here
}

答案 2 :(得分:0)

仍然可以按顺序遍历您的页面,尽管猜测模式会更难。只要根模式是连续的,你最终会遇到一个问题(假设它实际上是一个问题,而不仅仅是你不喜欢的东西)。

您可以使用随机数作为ID。这样可以防止轻松猜测页面ID和页面顺序(再次,如果这很重要)。

答案 3 :(得分:0)

您还可以使用Hashids对您的ID进行编码/解码。

  

编写此代码的目的是将创建的ID放在可见的位置 - 比如URL。

  

Hashids是一个小型的开源库,可以从数字中生成简短,独特,非连续的ID   它将像347这样的数字转换为像“yr8”这样的字符串,或者像[27,986]这样的数字数组转换为“3kTMd”。
  您还可以解码这些ID。这可以将多个参数捆绑到一个参数中,或者简单地将它们用作短UID。

答案 4 :(得分:-1)

我不打扰这个“问题”,但无论如何我在我的一个项目上用过这样的方法:

将新页面保存到数据库后,我生成了md5 of (record_id + page_title)并将其放入特殊字段pagecode。然后我通过页面代码而不是id访问页面。最好将数据库中的pagecode字段编入索引。

答案 5 :(得分:-2)

  

网站访问者可以查看ID   并简单地走过所有的   不同的内容页面。这个   当然不应该是可能的。

我不确定为什么这应该是一个问题 - 人们可以通过在Google中输入site:domain.com来查看网站上所有(公开的,Googlebot索引的)网页的列表,并且应该循环显示它们他们希望。更改您使用的唯一索引不会改变它。

但如果你真的不希望访问者直接访问你的网页,一个简单的快速修复是使用POST而不是GET。