5种密码安全性设计
密码就是打开大门的钥匙,要是不保管好,一旦被窃取、丢失、复制,别人就可以随意进出,就没有任何隐私和安全可讲。因此,在进行系统设计时,密码相关功能就是重中之重,千万不可以大意。
密码安全性设计主要有5种:密码复杂度设计、密码安全检查设计、密码失效设计、账户锁定设计、密码传输和存储设计。
5.3.1 密码复杂度设计
提升密码复杂度是一种性价比最高的处理方式。例如,在用户注册时,密码长度必须大于等于8位,必须同时包含数字、大小写字母及特殊字符,这样就可以很好地保障密码安全。
安全性和用户体验总是成对出现的,系统安全性越高,往往用户体验度越低。密码复杂度越高,安全性越高,但是用户要录入的内容就会变多,记忆和使用难度加大。密码复杂度越低,安全性 越低,密码被破解的可能性就会提高,但是用户记忆和使用会更加方便。
如何抉择?这就要根据系统的安全等级要求而定。如果是财务、银行、保险、资金划拨等重要系统,则一般强制要求采用最高的密码复杂度。如果是娱乐、休闲类系统,则只会提醒用户的密码安全等级偏低,而不会强制要求。为了兼顾安全性和用户体验,可以根据系统特点限定密码的安全等级,可以通过以下方法设计密码复杂度。
表5-1所示为密码复杂度计算指标的定义说明,不同的密码组合可通过此表计算不同的得分。
表5-1 密码复杂度计算指标的定义说明
根据密码复杂度的得分与密码复杂度评级标准进行对照,就可以
评估出密码的安全等级。密码安全等级划分为7个级别,如表5-2所示。
表5-2 密码复杂度评级标准
5.3.2 密码安全检查设计
为了防止用户随意设置过于简单的密码(如123456、1q2w3e
等),或者经常被攻击的、易破解的密码,可以使用密码安全检查库来增强密码安全性。
密码安全检查库中存储着所有不建议设置的密码,如123456、 abc123、1q2w3ed等,当用户进行密码设置时进行比对,如果匹配,则提示“您设置的密码不安全,请更换”。
密码安全检查流程如图5-8所示,包含以下3个步骤。
(1) 用户提交要设置的密码。
(2) 服务端使用此密码到密码安全检查库中进行检索。
(3) 如果有匹配数据,则返回密码存在风险。
图5-8 密码安全检查流程
这种设计思想就是病毒库的思想,杀毒软件都会有自己的病毒库,通过收集漏洞和用户的反馈,不断地完善病毒库。扫描病毒时,就是与病毒库比对的过程。也可以将密码安全检查库当作一种病毒库来看待。
这种设计还有一个变种,就是历史密码库比对,该设计的前提是必须存储用户使用过的所有历史密码,在用户注册、修改密码、重置密码时都要进行记录。
历史密码库检查流程如图5-9所示,包含以下3个步骤。
(1) 用户提交要设置的密码。
(2) 服务端使用此密码到用户历史密码库中进行检索。
(3) 如果有匹配数据,则返回“您曾经使用过该密码,请更换”。
图5-9 历史密码库检查流程
5.3.3 密码失效设计
大多数人都没有定期更换密码的习惯,所以密码遗失或被破解的概率就比较高,因此对于高安全等级的系统,可以采用密码失效策略。
例如,在用户注册、修改密码时,可以设置存储该密码的有效期为90天,当90天后用户再次登录,则会提示用户密码过期,并跳转至密码修改页面,要求用户输入用户名、原始密码、新密码进行更换。
对于密码失效的天数设置可以根据系统的安全等级进行配置,如 30天、3个月、1年等。密码失效是一种十分有效的安全措施,为了避免用户每次密码失效时都设置相同的密码,或者几个密码反复使用,一般密码失效策略要与历史密码库同时使用,确保用户定期更换不同的密码。
5.3.4 账户锁定设计
在使用银行ATM机时,如果同一天连续错误输入3次密码,则银行卡就会被吞,并且账户进入锁定状态而无法操作。在一些高级别的安全系统中,如果用户连续错误输入多次密码,则密码被锁定,这种设计存在多种变种,从而达到不同的用户体验。
用户连续错误输入N次,则自动进入锁定状态,必须等待N小时之后才可以再次重试,每次输入错误都会提醒用户当前剩余的可重试次数。这种设计方式既保证了安全性,也提升了用户体验。
用户连续错误输入N次,则自动进入锁定状态,并且必须人工介入,才可以恢复正常。这种一般为银行或金融类软件为了保证绝对安全所采用的方式。
5.3.5 密码传输和存储设计
密码在传输过程中为了防止网络嗅探,可使用HTTPS进行传输;为了防止在客户端和服务端被泄露,则需要进行加密。
早期密码都是采用MD5算法进行单次哈希的方式加密的,但是随着技术的发展,这种方式已经不够安全了,算法过于简单,容易被暴力破解。因此,可以采用加盐(salt)的方式来设计。所谓加盐,就是增加一个只有自己知道的字符串,一起参与加密,从而让原来的“味道”变了,这样可以保证密码存储在数据库中也不会被窃取。加密算法:MD5(MD5(原始密码)+ salt)= 加密后的密码。
例如,原始密码=123456,salt=abcdef,则加密后的密码
=MD5(MD5(123456)+abcdef)。
安全设计:盐并不是固定不变的,而是每个用户都是不同的(随机产生),并且在用户修改密码时可以修改,从而带来更高的安全性。一般采用表5-3所示的结构进行存储。
表5-3 用户密码存储结构示例
例如,使用yinhongliang这个账号进行登录,交互流程如图5-10所示。
(1) 使用用户名yinhongliang、密码123456登录。
(2) 服务端接收到请求后,使用用户名yinhongliang到数据库中查询用户数据,得到salt=abcdef,
password=14e1b600b1fd579f47433b88e8d85291。
(3) 使用MD5(MD5(123456)+abcdef)进行加密,得到加密后的密码。
(4) 使用加密后的密码与数据库中获取的password做比对。
(5) 根据密码比对结果,向用户返回登录成功或密码错误。
图5-10 密码加密加盐交互流程
思考1:还有更安全的方法吗?
只要增加密码被破解的成本,提高加密的复杂度的方法都可以,如可以做多次加密:MD5(MD5(MD5(密码))),MD5(MD5(密码)+
MD5(密码))。或者更换更为安全的算法,如SHA1、SHA256(又称为
SHA2)等。因此,可以设计各种个性化的加密方法来提高破解复杂度。
思考2:加密变得复杂,会有什么负面影响吗?
加密算法越复杂,对服务器的性能要求越高,因为加密属于非常耗CPU的操作,在高并发的场景下也会导致CPU占用率升高。由于在用户登录、修改密码、重置密码的过程中都会进行密码加密的操作,所以对接口的响应速度也会产生一定的影响。