当用户忘记密码时,不应该通过电子邮件发送。在他的Pluralsight课程中;首先破解自己:如何进行网络攻击",Troy Hunt指出;在SMTP上没有隐含的传输层安全性。信息安全堆栈Exchange上的这个答案证实了以明文形式发送或存储密码(包括通过电子邮件)是个坏主意。
重置密码的正确方法似乎是不要立即重置。相反,通过电子邮件向用户发送一个有时间限制的激活链接。这需要用户的手动干预,并且在任何阶段都不会通过电子邮件传递密码。
上述信息安全答案描述了如何实现密码重置机制:
无论如何都不要重置用户的密码——"重置"密码对用户来说更难记住,这意味着他/她必须更改或写下来——比如说,在显示器边缘的亮黄色便利贴上。相反,只是让用户立即选择一个新的——这是他们无论如何都想做的。
如果用户忘记了密码,请使用存储在数据库中的随机生成的重置令牌向他们发送一个安全的一次性重置链接。令牌必须是唯一和机密的,因此在数据库中对令牌进行散列,并在使用链接时对其进行比较。
基于表单的网站认证的最终指南对实现进行了类似的描述:
始终对数据库中丢失的密码代码/令牌进行散列。同样,这段代码是密码等效的另一个例子,因此必须对其进行哈希处理,以防攻击者进入您的数据库。当请求丢失的密码代码时,将明文代码发送到用户的电子邮件地址,然后对其进行散列,将散列保存在数据库中,并丢弃原始密码。就像密码或持久登录令牌一样。
但是用户将如何真正知道新密码。它是否重置为某个默认值?它是否更改为随机生成的密码,需要以某种方式与用户通信?
在";首先破解自己:如何进行网络攻击",激活链接会将您带到一个表单,您可以在其中输入新密码。
如果你正在处理一个网站,在那里你可以进入并与网络应用程序交互,并选择自己的新密码,这可能没问题。但是使用像.NETWebneneneba API这样的东西,您与控制器上的操作交互,这些操作通常应该为您提供数据,而不是用户界面。你不能只是给他们一个链接,然后期望他们用它做点什么。
因此,如果您正在通过Web API进行身份验证,那么有什么有效和安全的方法可以让用户重置密码并将新密码传达给他们?
在这个场景中需要记住的是Web API只是一个API。尽管可能没有网站,但某个地方仍然有用户界面(实际的网站、WPF应用程序或移动应用程序都无关紧要)。因此,通常安全的"忘记密码"功能仍然可以实现。
然而,有一点不同。不发送链接,而是发送令牌本身。然后UI提供了输入令牌的位置。接下来的步骤如下:
- 想要重置密码的用户会转到UI中相应的"忘记的密码"屏幕
- 系统会提示用户输入用户名
- 令牌以明文形式发送到他关联的电子邮件地址。散列版本与到期日一起存储在数据库中,例如从现在起一小时
- 用户在下一个屏幕中输入令牌
- 如果令牌有效,则用户将进入一个屏幕,在该屏幕中,他可以输入新密码(无需输入旧密码-令牌已经对他进行了身份验证)
通过电子邮件发送明文令牌听起来可能有点像通过电子邮件发送密码。然而,它在短时间后过期的事实给了攻击者一个很小的使用机会。此外,令牌是一次性的,在使用时会被丢弃。
在这个问题中,您要解决两个概念:密码重置和所涉及的机制,以及向web API验证用户身份的正确方法。我认为区分它们并首先理解后者很重要。
假设您有一个web应用程序和一个受保护的资源(web API)。web API要求所有调用方必须通过某种机制进行身份验证。允许用户向web API认证的一种方式是直接向web API提供凭证,但这会带来许多其他问题,例如web API需要存储/维护/访问用户帐户信息、以这种方式沿线路发送密码的安全性弱点、web API在获得用户的原始凭证时必须代表用户行事的广泛范围等。
您可能听说过OAuth 2.0,它解决了这些问题。访问受保护资源(web API)的更好方法是添加授权层。例如,web应用程序会显示一个对话框,用于输入用户的凭据,然后将凭据发送到授权服务器并进行验证,从而生成访问令牌。访问令牌然后可以用于代表用户(或代表使用客户端证书授予的应用程序)验证对web API的调用。使用这个流,web API不需要直接验证用户,它可以更加轻量级,并且解决了其他流的许多其他安全问题。有关更多详细信息,请参阅OAuth 2.0规范。
回到您的例子,一个更好的答案是您在不同的级别管理密码重置。您的web API根本不需要知道用户和密码,更不用说重置它了——它只需要接收一个令牌并验证它。这允许您使用所需的密码重置方法,并且不会影响对任何下游资源的访问。