【发布时间】:2020-04-16 22:52:05
【问题描述】:
我正在编写php 时事通讯脚本。我有一个MySQL 订阅者表,其中每个用户都分配了一个UUID,我想知道在取消订阅链接中使用它是否足够安全。
我通过替换href 属性以及与用户电子邮件匹配的query 和UUID 来构建它:
// Get UUID based on submitted email
$link = "href='https://example.com/unsubscribe.php?id=$uuid'>unsubscribe</a>)";
$html_message = file_get_contents('welcome_template.html');
$html_message = str_replace('href="">unsubscribe</a>', $link, $html_message);
// Headers and stuff
mail($email, $respond_subject, $html_message, $headers, '-fhello@example.com');
足够安全我的意思是如果它被认为是一种不好的做法,并且在一些查询之后预测UUID 是否“容易”。
This answer 到一个类似的问题指出
更简单的方法是将特定长度(例如 30 个字符)的随机字符串存储在对该字段具有唯一约束的表中。
UUID是一个有效的随机字符串吗?
【问题讨论】:
-
您使用的是什么类型的 UUID?如果只使用 MySQL 的默认
UUID()函数,那么不,它不安全。您应该包含第二次验证以匹配UUID,例如电子邮件、哈希或随机数,否则数字生成器可以通过简单地更改前 9-14 个字符轻松暴力破解 UUID。 -
如果是UUID version 4 (aka Random UUID),一般认为是“不可猜测”。如果它是基于 sequence 生成器的 UUID(因此是关于 MySQL 版本的评论),那么没有那么多.. 手动生成 30 个字符的 random 序列与使用random UUID 生成器,它归结为使用的随机数的质量。两者都可以存储在数据库中。
-
@fyrye 我正在使用 MySQL 的默认
UUID()函数,是的。所以您的建议是例如在 URL 中添加?email=$email,然后在取消订阅脚本中进行比较? -
我会不在 URL 中包含原始电子邮件。这会泄露更多信息。使用适当的 random 令牌源(这 不是 MySQL 中的默认
UUID(),如前所述) - 鉴于足够大的输出空间(a UUID 很好)和随机化(MySQL 中的UUID()不是)。另一种方法可能是在 URL 中传输电子邮件的 hash 并对其使用辅助检查(使用 HMAC 将是此方法的扩展)。哈希,而不是原始电子邮件。 -
加密有点多 IMO,因为您实际上并不需要解码链接值,只需确保其他内容与链接中的 uuid 匹配,因为相应的用户与 UUID 和更改任何一个值都会使链接无效。正如我建议的 MD5,可以使用
SELECT users.email FROM users WHERE id = @uuid AND MD5(CONCAT(users.email, @salt)) = @hash;验证链接并使用SELECT id, MD5(CONCAT(users.email, @salt)) AS hash FROM users WHERE users.email = @email;生成链接