我创建了一种盐;md5(兰德(0,10000000)); (可能有更好的方法?)
似乎不可能在 MYSQL 中使文本字段唯一。那么如何检查盐是否已经被以前的用户使用过呢?
或者我应该根据当前日期/时间生成盐吗?因为两个用户不可能同时注册,对吗?
对于盐来说,唯一性比长度和可预测性更重要。你假设攻击者有盐。
通用唯一标识符 (UUID) 是最好的,并且有一些示例可以在 php uniqueid()函数的文档页面上生成通用唯一标识符。与随机字符串相比,UUID 具有人类可读性和固定长度的优势,因此您可以将其存储在 varchar 字段中并使用唯一索引来确保永远不会重复。
使用 MD5 对时间进行散列是生成唯一值的常用方法,因为它具有固定长度并且是人类可读的。但是,仅生成一个固定长度的随机字符串并自己将其编码为十六进制更有意义。哈希不是为唯一性而设计的,因为它们被设计为不可逆的。使用散列函数可以保证冲突,尽管与 SHA1 的冲突会比 MD5 少。
盐的长度实际上只是一个因素,因为盐越长,它就越有可能是普遍独特的。
MySQL 的索引在文本字段上是有长度限制的,它们不会像在 char/varchar 字段上那样自动进入整个字段,因此没有实用的方法在文本字段上使用“唯一”键。
但是,如果您要存储由 MySQL 生成的哈希,则不需要文本 - has 结果是纯文本,因此只需使用固定长度的 char 字段:
mysql> select length(md5('a')), length(sha1('a'));
+------------------+-------------------+
| length(md5('a')) | length(sha1('a')) |
+------------------+-------------------+
| 32 | 40 |
+------------------+-------------------+
然后您可以对该字段应用唯一约束。
md5() 是一个损坏的算法,永远不应该被触及。
rand() 略有损坏,因为它基于系统时钟。
更好的方法是:
function generateRandomKey()
{
return base_convert(uniqid(mt_rand(), true), 16, 36);
}
编辑:如果有更好的方法或者我错了,请告诉我你的方法。我真的很感兴趣,想知道我是否不安全。
您可以使用http://php.net/manual/en/function.uniqid.php 之类的东西来生成 UUID。或者时间戳也是一个很好的 - 甚至可能是时间戳和 IP 地址或类似的。
使用用户 ID 和日期时间使用SHA1生成盐。
您通常不会经常生成盐字符串。所以当你第一次生成它们时,你应该做好。更长和更随机的字符串更好。
function generateSalt($length = null)
{
if (!is_int($length) || ($length < 1)) $length = 250;
do {
$salt[] = chr(mt_rand(0, 255));
} while (--$length);
return implode('', $salt);
}
更新新密码查询
update user set salt = :salt, password = sha1(concat(:password, :salt)) where id = :id limit 1;
您可以检查密码是否正确并同时获取用户数据。
select * from user where id = :id and password = sha1(concat(:password, salt)) limit 1;