[英]How to make this login/redirect method more secure
我有一个向用户发送电子邮件的应用程序,每个电子邮件都包含用户必须访问的页面的链接。
链接是唯一ID +随机数的md5。
链接看起来像: www.domain.com/index.php?id_page=<the md5>
在索引页面上,我将$_GET["id_page"]
在会话变量$_SESSION["id_page"]
,并将用户重定向到他必须看到的页面(仅当链接时,用户才被重定向到该页面)包含id_page
)。
如何改进此方法并使其更安全? 如何保证用户输入为其指定的页面,并且不能输入其他页面?
您可以在URL中添加他们的电子邮件。 某人猜测别人的电子邮件和相关哈希的概率仅为0。
您在这里关心的只是时间问题,而不是安全性问题:)。 如果您允许任何人猜测无限数量的id_page值,那么在给定足够的时间后,最终将有人偶然遇到一个有效的id_page值。
对此的唯一真正的防御措施是增加哈希的长度,使它在随机有效的id_page上(平均数月或数年)花费(平均)更多的时间。 这可以通过使用sha256或sha512而不是md5来完成。
另一种方法是,如果某人在id_page值上有3次连续不正确的猜测,则将他们锁定一段时间。 这将大大减少它们在给定时间段内可以尝试的值的数量。
最后,如果用户在重定向时已经登录,那么您也可以将生成的哈希存储在数据库表中。 这样,您可以将特定的哈希映射到表中的一个且只有一个userid。 如果用户尝试访问数据库中不对应的哈希页,则可以将其重定向到其他位置。
一种可以很好地防止猜测ID号的方法是在ID中添加某种填充,然后将其转换为base32。 当然,这并不能消除完全猜测ID的能力,但是对于任何偷窥的人来说,确实要花费更多的时间。
如果您具有URL www.domain.com/index.php?id_page=1,则可以将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 1实际上正在被填充成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。 上面的示例中的padding方法非常简单,但是它为您提供了解决问题的整体思路。
不要理会散列或创建唯一的ID或其他任何东西。 复杂性不会帮助您。
相反,只需生成一个随机令牌,然后使用它即可。 256位随机令牌应该足以完成您需要做的任何事情。
因此,使用mcrypt
(核心扩展):
$token = strtr(
base64_encode(mcrypt_create_iv(256/8, MCRYPT_DEV_URANDOM)),
'+/',
'-_'
);
这将为您提供字母a-zA-Z0-9-_
的44个字符的结果,其中包含256位随机熵。
无需哈希结果或其他任何东西。 随机数据就足够了。
要了解原因,您需要了解生日问题 。
基本上具有256位随机值,要使2个令牌发生冲突的可能性为1%,您需要生成4.8e37个令牌(48个后跟36个0)。
为了获得10e-18的碰撞机会(通常被视为安全的),您需要生成4.8e29令牌。
由于这些数字比您生成的数字多得多,因此两个令牌碰撞的机会非常小。
另一个问题是人们猜测令牌。 好吧, MCRYPT_DEV_URANDOM
使用底层操作系统的随机池。 这意味着人们比猜测这里生成的令牌更有可能猜测您的“唯一ID和随机数”。
因此,简而言之,只需使用随机令牌并完成:-)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.