MySQL和PHP中的唯一文本字段

5

我使用了md5(rand(0,10000000))创建了一个盐值;(可能有更好的方法吗?)

在MYSQL中似乎无法使文本字段唯一。那么,我该如何检查是否已经为先前的用户使用了盐值?

或者,我应该基于当前日期/时间生成盐值?因为不可能有两个用户在完全相同的时间注册,对吗?


1
你可以在一个varchar字段上添加唯一约束 - 这样你就可以检查重复的盐。 - thetaiko
6个回答

1

MySQL的索引在文本字段上是有长度限制的,它们不像char/varchar字段那样自动覆盖整个字段,因此在文本字段上使用“唯一”键没有实际意义。

但是,如果您要存储由MySQL生成的哈希值,则不需要文本 - 哈希结果是纯文本,因此只需使用固定长度的char字段:

mysql> select length(md5('a')), length(sha1('a'));
+------------------+-------------------+
| length(md5('a')) | length(sha1('a')) |
+------------------+-------------------+
|               32 |                40 | 
+------------------+-------------------+

然后你可以对该字段应用唯一约束。


1

对于盐来说,独一无二比长度和可预测性更重要。你要假设攻击者已经知道了盐。

最好使用通用唯一标识符(UUID),在 php 的 uniqueid() 函数的文档页面上有生成通用唯一标识符的示例。UUID 优于随机字符串的优点在于它是人类可读的且长度固定,因此可以将其存储在 varchar 字段中,并使用唯一索引来确保没有重复。

使用 MD5 哈希时间是生成唯一值的常见方法,因为它具有固定长度且易于阅读。但是,最好生成一个固定长度的随机字符串并自己将其编码为十六进制。哈希不是为了独一无二而设计的,而是为了不可逆转。使用哈希函数会导致冲突,尽管 SHA1 比 MD5 冲突更少。

盐的长度实际上只是一个因素,因为盐越长,它就越有可能是通用唯一的。


如果两个拥有相同盐值的用户恰好决定设置相同的密码,那应该是一种奇怪的巧合。 - Jonathan.
@Jonathan,如果有相同的盐值但是密码摘要不同的话,我会先攻击那些账户,因为这样可以更好地找到成功的碰撞。两个具有相同盐值和密码的账户相当于攻击者只需要付出一次攻击的代价就可以得到两个账户,但攻击者并没有任何优惠。 - Marcus Adams

0

md5()是一个有缺陷的算法,不应该使用。

rand()略有缺陷,因为它基于系统时钟。

更好的方法是:

function generateRandomKey()
{
    return base_convert(uniqid(mt_rand(), true), 16, 36);
}

编辑:如果有更好的方法或者我错了,请展示你的做法。我真的很感兴趣,想知道是否我太不自信了。


1
有关更广为接受的观点,请参见https://dev59.com/JHE95IYBdhLWcg3wY9D6 - dkretz
@ledorifier,您发布的链接是关于哈希密码而不是生成随机盐的。 - Marcus Adams
1
而 http://stackoverflow.com/questions/157998/whats-the-difference-between-sha-and-md5-in-php。我指的是“……永远不会被触摸。” - dkretz
生成盐值不需要是安全的,如果攻击者真的想要找到创建盐值的数字,那么就由他们浪费时间。 - Jonathan.

0

通常情况下不会经常生成盐字符串。因此,当您首次生成它们时,应该做得很好。长度更长、更随机的字符串更好。

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;

0

0

使用用户ID和日期时间生成SHA1盐值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接