您的系统可能正在发送一些电子邮件。 有时,这些电子邮件包含指向网站公共部分的链接,有时它们具有指向受身份验证保护的部分的链接。 无论哪种方式,如果将电子邮件发送给注册用户(而不是仅订阅的电子邮件),则都不应使用户键入用户名和密码。 即使是站点的公共部分,用户也可能想要做一些需要对您显示的内容进行身份验证的操作,例如将其添加到收藏夹中。 但是,对于公共内容来说有些棘手,并且您可能不希望将其放在那里,因为用户倾向于转发“摘要”或“本周最佳”电子邮件,然后收件人甚至可以在不知情的情况下冒充他们。
无论如何,当用户单击系统发送的电子邮件中的链接时,他们可能是
自动登录。 我认为这是许多系统应具备的产品要求,而且听起来很合理。 但是我很少见到。假设您喜欢它,并且想要在系统中实现它。 肯定有一些安全隐患,该怎么做?
- 对于发送的每个电子邮件,生成一个令牌。 令牌应为HMAC(用户的电子邮件(或用户名或ID)与令牌生成时间戳串联)
- 为HMAC使用应用程序范围的,可配置的每个环境密钥。 还请使用良好的哈希算法,例如SHA-256(而非MD5)
- 将令牌附加到电子邮件中的每个链接。 您可能正在使用电子邮件模板,所以每个链接都带有
?emailLoginToken=${token}
。 还要将电子邮件和时间戳作为参数传递。 - 有一个过滤器/拦截器来查找该特定的参数名称,如果找到了该名称,请调用令牌身份验证逻辑(如下所述)
- 使用传递的参数(电子邮件和时间戳)重做HMAC,并将其与令牌参数进行比较
- 检查令牌是否仍然有效–您可以有一个有效期,并且在生成令牌后超过2周不允许使用令牌。
- 如果一切正常(传递的令牌和重做HMAC的结果相同),请登录用户(发送会话cookie)。 但是(在会话中)添加一个标志,表明登录是通过令牌进行的。 然后,未经密码确认,不允许更改密码,电子邮件或任何“敏感”操作。 如果已实现,请使用与“记住我”登录名相同的条件。
- 让所有此类链接都通过https
还有另一种稍微不同的情况。 无需使用hmac并发送所有参数,只需将令牌生成为电子邮件和时间戳的哈希值,并将其(和时间戳)存储在数据库中,并使用外键到users表。 在这种情况下,真实性确认来自于在数据库中找到它的事实,而不是通过验证HMAC来实现的。 然后,当令牌作为参数出现时,只需在数据库中查找它即可。 您仍应将用户的电子邮件作为参数传递,并将传递的电子邮件参数与对应于持久令牌的用户电子邮件进行比较(以避免猜测)。 成功登录后,您可以删除令牌。 您可能决定不执行此操作,并安排了一个清理X周之前的令牌的计划作业。 如果立即删除它,它将更加安全。 如果您保留它,它将使用户可以再次打开相同的邮件,并且登录仍然有效。 这种方法使您可以根据需要使令牌无效。 例如,如果用户决定更改其密码或电子邮件,则可以使所有令牌失效。
这似乎是一个艰巨的过程,但实施起来相当容易。 困难的部分是要考虑所有要点,而不要损害安全性。 请注意,安全性是此处的重要方面。 正如在reddit上指出的那样,电子邮件可能是不安全的–当用户通过不安全的POP3(使用Outlook,Thunderbird等)下载电子邮件时,攻击者可能会获得链接并冒充用户。 这就是为什么您应该限制用户通过令牌登录时可以执行的操作。 这可能无关紧要,因为大多数用户使用Webmail或受保护的POP3或内部电子邮件服务器。 但是,例如,对于银行软件,您不应这样做。 但是,在链接中包含令牌可能比密码重置链接的问题少,但也可以用相同的方式来拦截。 但我可能会在另一篇文章中进行讨论。
解决安全性问题时,您可以采取的另一步骤是将令牌身份验证限制为用户最常使用的IP地址。 总体而言,上述方法比安全风险更具优势,因此,我认为任何主流站点都应实施(考虑到所有安全隐患)。
翻译自: https://www.javacodegeeks.com/2013/05/login-tokens-in-email-links.html