PHP / Mail / MySQL: 注册邮件确认

4

我不熟悉PHP/MySQL和电子邮件。我相信这个问题已经被问过了,但我找不到它。如果这很麻烦,我向您道歉并提前感谢您!

有没有可能做一些事情,让用户必须先点击电子邮件中的链接,然后再将用户添加到数据库中?

而且你知道吗,对于一些网站,他们为每个电子邮件验证创建一个唯一的网址(在图片中显示为红色)?他们如何为每个电子邮件创建一个唯一的网页?


图片来源:https://kayako.atlassian.net/wiki/download/attachments/5734920/subs-validation.png?version=1&modificationDate=1291956283000&api=v2


enter image description here

非常感谢您的关注!如果可能的话,我更喜欢没有可以复制和粘贴的直接脚本,因为我喜欢自己找出来:P但请给我一些提示,因为我完全迷失了。

如果有任何不清楚的地方,请告诉我,我会尽力澄清!


1
访问此链接:https://dev59.com/93I95IYBdhLWcg3w7SlZ - Dipnesh Parakhiya
非常好的问题。您可以像我在下面的答案中所做的那样,简单地构建链接,例如 example.com/activate.php?code=a2ef24...。格式化为您看到的URL将使用.htaccess规则在幕后重写,以看起来与此完全相同。 - BeetleJuice
3个回答

5

注册流程

  1. 用户填写一个包括电子邮件和密码在内的基本信息表格,并将表单提交给register.php

  2. register.php将用户信息添加到临时位置,例如包含所有用户提交的字段以及过期时间expiration和激活码activation_code字段的pending_users表。该代码可以是任意随机、无法猜测的值。例如:hash('sha1', mt_rand(10000,99999).md_rand(10000,99999))。只要不做任何可预知的事情,比如哈希当前时间或用户名。

  3. register.php向用户发送一封电子邮件,其中包含一个URL,链接到activate.php并包含激活码。例如:example.com/activate.php?code=a2ef24... 该电子邮件还应告知用户过期时间(1到12小时有效期对我来说似乎可以接受)

  4. 当用户点击链接时,她会触发一个GET请求到activate.php。这样做,用户就证明了自己拥有该电子邮件地址

  5. activate.php从请求参数(例如$code=$_GET['code'])中获取代码。使用该代码,脚本查询pending_users表以获取与该代码匹配的记录。

  6. 如果找到了该代码,请在继续之前检查它是否已过期。过期时间可以防止随后进入用户帐户的其他人完成注册。

  7. 如果代码有效,请从匹配的记录中捕获用户详细信息并将该记录从pending_users表中删除。

  8. 在常规的users表中编写匹配的记录。在完成此操作之前,用户无法登录,因为登录脚本仅检查users表,并忽略pending_users表。

  9. 注册完成。

安全注意事项:

为了保护您的用户,请勿以明文存储密码。当您从注册表单(例如$_POST['pwd'])接收它时,请执行以下操作:

$pwd = $_POST['pwd'];

//first validate; it should meet minimum requirements

$pwd_hash = password_hash($pwd, PASSWORD_DEFAULT); // <- the hash gets stored

稍后,要验证密码,请执行以下操作:
password_verify($cleartext_pwd, $pwd_hash);

如果密码正确,则返回true;否则返回false

安全注意事项II:

为了您的保护,请永远不要直接插入用户提供的值到您的数据库查询中。这意味着来自外部的任何值,不仅仅是用户名、电子邮件、密码等等,还包括从用户获取的值,例如上面的activation_code、cookie 值或者头信息(例如User-Agent)。相反,学习使用预处理语句。这将保护您免受SQL注入攻击。


我发送的电子邮件中,指向验证页面的链接是:http://localhost:8888/Brighten/admin/signup/validation.php?salt=cd16136f697c7264 但是当我实际点击它时,它变成了这样:http://localhost:8888/Brighten/admin/signup/validation.php?e6fc0ac809033f41 他们为什么要删除我的GET函数? - Ronald Ng
没有更多的信息,我无法确定。如果我是你,我会先确认错误。确保脚本实际上正在接收请求;然后执行 print_r($_GET) 来再次检查激活码是否未显示。如果确实如此,请打开一个新问题并询问相关内容。 - BeetleJuice
谢谢,这是一个非常好的指南!不过我有一个问题。为什么不将未确认的用户插入到主用户表中,并将其标记为未确认,以便他们仍然可以登录但权限受限?我曾经作为一个用户被锁定了,因为弄乱了电子邮件确认。我不得不用另一个电子邮件注册,然后联系客户支持手动删除我的第一个带有未确认电子邮件的帐户,以便我可以在第二个帐户中更改我的临时电子邮件为我的主要电子邮件。这花费了我们两个人相当多的时间。 - Arthur Tarasov
1
@ArthurTarasov,如果您想允许登录,这也是有道理的。或者,您的登录脚本还可以查看待处理用户表并允许从其中进行登录,但设置受限权限。在我的实现中,如果电子邮件验证从未完成,则会删除挂起记录,因此您稍后可以尝试使用相同的电子邮件进行注册,但使用新的验证代码。 - BeetleJuice

1

不确定在验证后是否可以添加数据到数据库...

当我想要做类似的事情时,我在用户表(或元用户表)中创建一个名为“validate”的数据。 如果这个数据是“true”,那么用户已经完成了验证,他可以使用他的账户。 如果它仍然设置为“false”,则用户没有验证他的帐户:他无法使用它。

通过这样做,您必须确保在用户尝试登录时帐户已经被验证,但这并不是大问题^^

希望这对您有所帮助。


非常有用,这是一个简单而不失优雅的方法,非常感谢! - Ronald Ng

1
这些不是唯一的网站,只有一个脚本用于验证注册完成。当用户点击链接时,通过服务器端的“请求重写”,所有传入的请求都被路由到同一个脚本中,以便随机令牌值作为参数可用于脚本执行。
脚本的功能:检查该随机令牌值是否存在于之前用户实际注册时生成并存储的数据库中。
对于该脚本剩下要做的事情就是删除确认随机令牌和/或设置标志,指示注册用户已通过单击链接确认其身份(电子邮件地址)。
简单明了,很难绕过,因为您无法猜测为哪个注册用户生成了什么随机令牌值而没有收到电子邮件。但请考虑到,如果攻击者知道该过程,使用匿名电子邮件服务(一次性电子邮件地址)接收和评估此类确认请求对于攻击脚本来说是微不足道的。

创建一个脚本,每当用户注册时创建哈希值,当用户单击邮件中的地址时,它会取走确认哈希值。 - Ronald Ng
我认为用“随机令牌”代替“哈希”更加合适。是的,脚本通常会删除该令牌,因为在确认步骤中正确提交了该令牌后就不再需要它了。顺便说一下:当您提供“忘记密码”功能时,您可以稍后重复使用该数据库列:创建一个新的令牌并将其发送到电子邮件地址,以允许用户进行一次性登录,以便他可以重置密码。 - arkascha

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