关于用户账户、授权和密码管理的12个最佳实践

翻译:zhangv
在处理用户账户、授权和密码管理时,有时情况会非常复杂。对很多开发者来说,账户管理时一个经常被忽视的问题。对产品经理和用户来说,结果常常是始料未及的。
幸运的是,Google云平台(GCP)包括了一些工具来帮助你安全地创建、处理用户账户。无论你负责的是架设在Google Kubernetes Engine上的网站,基于Apigee的API服务,使用Firebase的app,还是其他需要验证用户的服务,本文将展示给你一个安全、可扩展、可用的账户验证系统的一些最佳实践。
1 . 密码不要明文存储
我认为账户管理最重要的一条法则是:安全地存储敏感用户信息,包括密码。对待这些数据一定要慎重而合理。
在任何情况下都不要以明文来存储密码。你的服务应该存储足够强的密码不可逆加密摘要 — 使用类似PBKDF2,Argon2,Scrypt或Bcrypt来创建。摘要时还需要加入随机字符串(盐)。不要使用已经废弃的摘要算法,如MD5,SHA1,并且在任何情况下都不要使用可逆加密算法或者自己发明摘要算法。
在设计系统之初就要考虑到系统被黑的情况。问自己“如果今天数据库泄漏,用户是否会收到影响?我们可以做哪些补救措施?”
另一个问题:如果在用户提供给你密码后,你可以获得铭文的密码,那么你的实现方案就是有问题的。
2 .支持第三方的身份授权
第三方身份授权可以让你依赖外部的可靠服务来验证用户身份。Google, Facebook和Twitter是最常用的身份授权提供方。
你可以使用诸如 Firebase Auth的服务来帮助你整合外部身份认证授权。优点是:包括简单的管理界面,更不容易被攻击,多平台SDK。我们在下面会介绍更多特性。
3 . 分清楚用户身份和用户账户的区别
你的用户不是邮件地址,也不是电话号码,更不是OAuth服务返回的唯一标识。你的用户是他们在你的应用服务中的一系列个人数据和体验的累积。优秀的用户管理系统体现在用户个人数据各个部分设计上的低耦合和高内聚上。
用户账户和隐私信息的分离可以让你简化实现第三方身份授权的难度,并且可以允许用户修改用户名,将多个身份授权和同一个账户关联。实际操作中,每个用户拥有一个全局的身份标识,然后其他关联信息通过这个全局标识进行关联,而不是把这些所有的信息放到同一个数据记录上。
4 . 多个授权标识关联到一个账户
这个星期用户通过用户名和密码登录了你的服务,可能下星期会用Google的授权进行登录。这可能造成重复账户的问题。同理,用户可能会使用多个邮箱地址来使用你的服务。如果你将用户标识和认证分开,也就是可以更容易地链接多个标识到同一用户。
后端实现需要处理用户在注册过程中意识到他的第三方授权没有关联到他们已有的账户,这时就需要让用户提供一个共用的识别标识,比如邮箱地址、电话号码或者用户名。如果系统已经存在这些标识,那么就允许用户使用第三方授权认证,并将这个新的ID关联到已有账户。
5 . 不要阻止用户使用长或复杂的密码
NIST最近更新了关于密码复杂度和强度的建议。只要你使用了比较强的加密摘要算法,那么很多问题其实都不存在。无论输入长度是多少,摘要算法总是可以产生固定长度的输出,所以用户也就可以想用多长的密码都可以。如果一定要一个确定的密码长度,只要看一下服务器允许的最大POST请求的设置。通常是1MB。别慌。
你的密码摘要只包含一小部分已知的ASCII字符。如果不是,你可以将二进制的摘要进行Base64编码。因此,理论上,你可以允许用户在密码中使用任何字符。如果有人想使用克林贡语、Emoji或者控制字符,技术上也是允许的。
6 .不要制定不合理的用户名规则
网站或者服务通常会设置一些不合理的用户名规则,比如要求用户名应该至少两个或三个字符,不允许使用隐藏字符,不允许在用户名的前后使用空格。更有甚者,会要求用户名至少是八个字符,或者很粗暴的禁止任何非7位的ASCII字符集的字母和数字。
虽然严格的用户名限制可以让开发人员轻松一些,但是这些是以用户体验为代价的,设置可能驱使用户离开。
有些情况,最好的方法是分配用户名。如果你的服务适合这种情况,那就尽量让用户名尽量简单易记,方便沟通。字母数字ID可以避免视觉上的混淆,比如“Il100”。你也可以扫描字典来确保你的密码中不含有歧义。这个规则也适用于自动生成的密码。
7 .允许用户修改用户名
很多遗留系统和任何提供邮箱账号的平台不允许用户修改用户名。虽然有很好理由禁止被释放的用户名重新使用,但是长期用户还是会想要换个用户名而不需要创建一个新的账户。
你可以允许用户使用别名,然后让用户自行选择使用哪个别名,从而可以满足用户修改用户名的需要。你可以设置一些规则,比如有些机构仅允许每年修改一次用户名,或者只显示用户的主用户名。邮箱提供方需要确保用户在取消关联某个用户名时被告知了,或者禁止完全取消关联旧的用户名。
使用恰当的规则,但要确保允许用户后续可以修改。
8 .允许用户删除他们的账户
大量的服务没有自助的方法让用户删除他们的账户和相关数据。当然,谁也不想。这些考虑需要配合你的系统安全需求,但很多受限环境会提供具体的数据留存方法。通用的解决方案是让用户设定自动删除账户的时间。
某些环境下,你可能需要依法遵循用户的要求来定期地删除他们的数据。你也可以避免在数据泄漏事件中将那些已经“关闭”的账户信息泄漏。
9 .理性决定会话长度
安全和认证的会话长度通常被过度重视了。Google花了很大的力气去确保用户是他自己,并且会依据某些事件和行为来再次确认。用户可能需要多个步骤来提升账户的安全性。
你的服务的会话可能会因为某个非关键性的分析目的而一直处于打开状态,但是需要需要设置一个阈值,当达到这个阈值时需要输入密码、第二步认证或其他认证方式。
考虑经过多长时间来再次对用户进行认证。如果用户重置了密码,需要重新验证用户。如果用户修改某些核心账户信息或者进行敏感操作时,要求用户验证或者多重认证。考虑是否允许用户可以通过多个设备和地点同时登录。
当用户的会话过期或在要求用户重新验证时,尽量不要打断用户正在进行的操作,并且保留用户未保存的数据。让人沮丧的一种情况是:用户填写完一个很长的表单并提交后,才发现他们需要重新登录 – 并且所有填写的数据都丢失了。
10 .使用2步验证
如果选择2步认证(2重授权或 2FA),需要考虑当用户账户被窃取时的实际影响。短信2FA因为很多原因,已经被NIST废弃掉了,但是仍然是一个大多数用户乐于接受的选择。尽量提供安全的2FA方案。使用第三方授权服务,并借助他们的2FA是一个省钱省力的方法。
11 .用户ID大小写不敏感
你的用户可能不在意或不记得用户名的大小写。用户名应该完全大小写不敏感。常见的做法是保存用户名和邮箱地址时转化为小写字母,检查时也都转换为小写字母。
智能电话意味着不断增长的用户设备数量。很多都支持自动纠错和自动开头字母大写。在UI级别就阻止这种行为,而且你的服务需要能够处理这种未注意到的自动大写。
12 . 构建一个安全的认证系统
如果你在使用Firebase Auth,很多的安全问题都已经自动帮你处理了。但是你的服务还是需要优化以防止被滥用。一些核心的考量包括:使用密码重置而不是密码找回,详细的账户操作记录,登录尝试频率限制,如果账户被过多次尝试登录则锁定账户,在陌生设备上首次登录时或长时间未登录的账户使用2FA。还有很多其他的方面,可以参考下面的链接。
进一步阅读: