如何使此登录/重定向方法更安全

时间:2015-04-07 06:40:46

标签: javascript php security

我有一个向用户发送电子邮件的应用程序,每封电子邮件都包含指向用户必须访问的页面的链接。

该链接是唯一ID +随机数的md5。

链接如下:www.domain.com/index.php?id_page=<the md5>

在索引页面上,我将$_GET["id_page"]保存在会话变量$_SESSION["id_page"]中,然后将用户重定向到他必须看到的页面(仅当链接包含时,才会将用户重定向到该页面id_page)。

如何改进此方法并使其更安全?我如何保证用户进入指定给他们的页面 - 并且不能进入任何其他页面?

4 个答案:

答案 0 :(得分:1)

您可以在网址中添加他们的电子邮件。某人猜测别人的电子邮件和相关哈希的概率大约是0。

答案 1 :(得分:1)

你关注的是时间问题,而不是安全问题:)。如果你允许任何人猜测无限数量的id_page值,那么给定足够的时间,最终会有人发生随机有效的id_page值。

你唯一的真正的防御措施是增加哈希的长度,导致它(平均)在随机有效的id_page(大约几个月或几年)上花费更多时间)。这可以通过使用sha256或sha512而不是md5来实现。

另一种方法是将某人锁定一段时间,如果他们在id_page值上有3次连续的错误猜测。这将大大减少他们在给定时间内可以尝试的值的数量。

最后,如果用户在重定向时已经登录,那么您还可以将生成的哈希值存储在数据库表中。这样,您可以将特定哈希映射到表中的一个且只有一个用户ID。如果用户试图访问他们在数据库中不对应的哈希页面,那么您可以将它们重定向到其他位置。

答案 2 :(得分:1)

一种可以很好地防止猜测ID号的方法是在ID中添加某种填充,然后将其转换为base32。当然,这并没有消除完全猜测ID的能力,但它确实会让任何偷窥的人都花费更多的时间。

如果您的网址为www.domain.com/index.php?id_page=1,则可以将ID转换为应用中唯一的ID,例如:

填充ID = id x 9 - 2

7 = 1 x 9 - 2
16 = 2 x 9 -2
25 = 3 x 9 - 2

然后,您可以将新的填充ID转换为基数32,即

7 = G4
16 = GE3A
25 = GI2Q

然后新的url(id为1):

www.domain.com/index.php?id_page=G4

使用这种方法,如果有人猜到1-6的基数为32,那么它将返回404,因为你的ID实际上被填充为7.猜测8-15不会返回解析的ID,因为下一个id为2,填充为16,依此类推。

这不仅会使查询字符串的大小变小,而且也不会使用明显的MD5哈希值,这种哈希值很容易使用词典顺序浏览。

如果您希望将页面链接到特定用户,那么您没有理由不能将更多值附加到新的padded_id(让我们称之为哈希)。

例如,如果您的用户ID为12,并且您只希望该用户能够访问ID为10的页面,则需要创建包含以下两个值的哈希:

page_id(10)-user_id(12),使用上面的例子,这将产生:

(10 x 9 - 2) (12 x 9 - 2)
88-106
HA4A-GEYDM

您现在有一个很好的小散列链接,可以保护到单个用户ID。上面示例中的填充方法相当简单,但它可以让您全面了解如何解决问题。

答案 3 :(得分:1)

不要打扰散列或创建唯一的ID或任何东西。复杂性无助于你。

相反,只需生成一个随机令牌,然后使用它。 256位随机令牌应该足以满足您的任何需要。

所以,使用mcrypt(核心扩展名):

$token = strtr(
    base64_encode(mcrypt_create_iv(256/8, MCRYPT_DEV_URANDOM)), 
    '+/', 
    '-_'
);

这将为您提供44个字符的字母a-zA-Z0-9-_结果,其中包含256位随机熵。

无需对结果或任何内容进行哈希处理。随机数据就足够了。

要了解原因,您需要了解The Birthday Problem

基本上使用256位随机值,如果2个令牌发生碰撞的可能性为1%,则需要生成4.8e37令牌(即48后跟36 0)。

要获得10e-18碰撞的机会(通常被视为安全),您需要生成4.8e29令牌。

由于这些数字比你产生的数字更多,因此2个令牌碰撞的可能性极小。

另一个问题是人们猜测令牌。好吧,MCRYPT_DEV_URANDOM使用底层操作系统的随机池。这意味着人们更有可能猜测你的“唯一身份和随机数”,而不是猜测这里生成的令牌。

因此,简而言之,只需使用随机令牌即可: - )