电子邮件确认码的最佳做法

时间:2010-01-09 12:21:37

标签: php activation email-confirmation

我正在创建一个涉及用户注册的PHP网站,我想知道“电子邮件确认”代码的最佳做法。

新用户必须确认他们的电子邮件地址 - 我这样做是通过生成代码并通过电子邮件将其发送给用户,然后他可以使用该电子邮件激活他的帐户。我没有将这个密钥存储在数据库中,而是使用了一个方便的小解决方法:代码是以下结果:

md5("xxxxxxxxx".$username."xxxxxxxxxxx".$timestamp."xxxxxxxxx");

其中$ timestamp是指用户创建时间。总的来说,我对此非常满意,但后来我开始思考,这是否足够安全?碰撞的可能性怎么样?我还需要生成密码重置等代码。如果我使用类似的方法,碰撞可能导致一个用户无意中重置另一个用户的密码。这没有用。

那你怎么做这些事情?我的想法是以下格式的表格:

codePK (int, a-I), userID (int), type (int), code (varchar 32), date (timestamp)

其中'type'为1,2或3表示“激活”,“电子邮件更改”或“密码重置”。这是一个很好的方式吗?你有更好的方法吗?

使用与上述类似的方法,我可以在不使用cron-jobs的情况下自动删除两天以上的任何内容吗?我的主人(almostfreespeech.net)不支持他们。如果可能的话,我想避免在外部主机上有一个cron-job,这是一个删除东西的脚本,因为那只是凌乱= P。

谢谢!
马拉

更新
澄清:我已经意识到安全和安全地执行此任务的唯一方法是使用数据库,这是原始功能试图避免的。我的问题是如何构建表(或表?)。有人建议我不再使用codePK,只需将代码设为PK即可。简而言之,我的问题是:这就是你做的吗?

5 个答案:

答案 0 :(得分:10)

当我需要这些技巧时,通常是两个原因之一,两者都提到了:

  1. 用作发送给用户的验证电子邮件的密钥
  2. 用作密码重置链接的密钥
  3. 当然会有很多其他场合你会考虑使用这样的结构。

    首先,你应该总是使用某种隐藏的盐,只有你知道。请注意,每个用户的盐应该不同。例如,盐可以计算为sha256(something random)。然后应将此盐与用户名和密码一起存储在数据库中(使用盐进行哈希处理)。

    发送密码重置链接时我要做的是创建另一个盐(不要让用户访问任何用盐进行哈希处理的东西。他知道他的密码,所以使用暴力可以找出你的盐)。另一个盐,它本质上只是一个随机字符串的哈希值(你可能想在这里找到md5,因为你提到长度是一个问题),你应该保存到你的数据库中。

    通常,您可以在向users表中添加其他列。但是,这也有一些问题,主要是一旦密码被重置或用户被激活,你将从数据库中删除密钥,这导致大多数行具有空值,这反过来又带来一些其他麻烦

    这基本上归结为:

    • 使用针对用户的唯一盐(可能是全局的秘密盐)来散列用户的密码。
    • 通过散列一些随机或伪随机来源(如时间戳,mt_rand()甚至random.org来生成密钥,如果你真的想要随机的话。
    • 切勿使用您的全局盐或用户独有的盐来散列用户可以访问的任何内容,包括密码重置键,激活密钥等。

    请注意,我绝不是安全专家,我可能已经忘记了许多事情,我可能已经提到了一些非常糟糕的做法。只需我5美分; - )

答案 1 :(得分:2)

为什么使用任何用户的数据作为授权密钥的基础?

我认为你将去激活的数据存储在一个数据库中,所以为什么不添加一个只是一个随机密钥的附加记录(可能是带有一些额外操作的md5'ed uniqid)然后检查对此?

答案 2 :(得分:1)

直到你在互联网上发布你的方法为止,这是足够安全的!这是因为你依靠默默无闻的安全,这不是一个好主意。

你应该使用某种键控哈希函数或理想的MAC,它包含一个只有你知道的密钥。

答案 3 :(得分:0)

为什么不使代码字段成为唯一索引?那么永远不会有碰撞吗?

此外,如果您不需要从用户输入创建哈希并将其与数据库哈希(电子邮件确认,密码重置等)匹配 - 您可以将随机字符串添加到哈希体,如 md5('xxx'.$username.'xxx'.time().'xxx'.rand())

答案 4 :(得分:0)

为什么不让用户输入他们的用户名他们的代码,从而消除碰撞的任何问题?你不会丢失任何安全措施,因为你仍然要求他们从电子邮件中获取密钥,但是你可以阻止他们重置其他用户的密码。