编辑:我发现并发布了一个高效优雅的解决方案,可将
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;
}
其他问题:
我的功能的反向功能是什么?
我希望你能帮助我。谢谢!
答案 0 :(得分:8)
用户可以通过网站访问这些页面吗?如果答案是肯定的,那么你应该问问自己这是否真的是一个问题。
如果没有,那么问题在于你没有保护你的网页或换一种方式:你依靠默默无闻的安全,这绝不是一个好的举动。
我的建议?保护您的网页,以便只有合适的用户才能访问它们,或者不用担心它。
如果你真的必须担心它,只需传递一个对于给定页面必须正确的额外字段。我不会从ID构造这个。在数据库中创建页面条目时,可能会生成另一个数字或GUID。如果两个字段都不正确,则不要显示该页面。
忘记简单的字符替换和其他天真的混淆技术。他们浪费你的时间。
编辑:如果您使用的是相同长度的非顺序ID,请考虑使用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。