登录过程中密码的安全和攻击风险
前言
我们在开发app客户端的时候,最主要的一个模块就是用户登陆模块,其中用户密码的验证和保存流程是极易引起安全风险,各种注入攻击、重放攻击、拖库风险等,都会危机到用户的账号安全,今天从用户登陆密码验证流程角度探讨下密码安全。
1 服务器端不要保存密码明文
首先,服务器端不要保存密码明文,因为攻击者甚至不需要很高深的技术,利用SQL注入就可以获取所有的明文密码,后果严重。
SQL注入: 它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力, 它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。
假设我们在浏览器中输入URL www.sample.com,由于它只是对页面的简单请求无需对数据库动进行动态请求,所以它不存在SQL Injection,当我们输入www.sample.com?testid=23时,我们在URL中传递变量testid,并且提供值为23,由于它是对数据库进行动态查询的请求(其中?testid=23表示数据库查询变量),所以我们可以在该URL中嵌入恶意SQL语句。
2 服务器端也不能保存密码的哈希值
按理说哈希值是单向的,不可能被逆向,但是这世界上竟然
有查表(彩虹表)攻击。
彩虹表攻击: 攻击者可以先行建立一张"所有"明文密码到哈希值的对应表,这样拿到一个哈希值几秒钟就能获取其对应的明文密码。假设网站有10万注册用户,并且其中10%的用户密码很简单,那攻击者通过简单的查表也许几个小时就能获得这1万用户的明文密码。
3 密码加盐
服务器端的密码应该保存"加盐"(salting password)后的哈希值,
加盐: 所谓加盐是指在密码前加一串随机字符串,注意不能用固定的字符串加盐,因为假如盐固定,那攻击者还是能事先建立起彩虹表,那就回到了上面的规则2,所以应该每个用户用不同的随机盐。
怎么保证每个用户不同的盐值:
可以简单的,定义一种算法,将用户ID变换成盐值。
也可以通过一定机制弄成随机盐,更加安全。
4 注意客户端保存的密码
因为有自动登录的要求,所以客户端也有保存用户密码的需求,客户端密码更应注意密码安全,客户端保存密码的规则可以参照服务器保存密码的规则。
5 避免传送明文密码
客户端不能传送明文密码到服务器作登录校验,在用户和服务器之间有太多恶意设备的可能(嗅探,代理,AP,路由器…),有的客户端甚至用GET传递明文密码,那普通的代理log就把用户密码给泄露了。
6 避免直接传送密码哈希
客户端也不能传送密码哈希值到服务器,一个原因是规则2的彩虹表,另一个原因是对于你个人,黑客甚至不需要破解到明文密码,复用这个哈希值就可以登录某人账户了。
7 不能把加盐的哈希值传到服务器
虽然客户端传送加盐的哈希值可以避免彩虹表攻击,但是由于该哈希值是固定的,黑客还是能复用该值,进行重放攻击。
8 增加随机数一起做哈希
作为登录校验的值必须是不固定的,由于密码和盐是固定的,所以必须加入个随机值一起做哈希。客户端可以预先从服务器处获取个随机值(比如时间戳),然后和加了盐的密码哈希再哈希一次。这样就算是中间人(MITM)攻击也无效。
使用随机值哈希流程:
(1) 认证服务器内部产生一个随机数,作为Challenge,发送给用户;
(2)客户将口令和随机数合并,使用单向Hash函数 ( 例如MD5算法 ) 生成一个字节串作为Response;
(3)认证服务器将Response与自己的计算结果比较,如两者相同,则通过一次认证,反之认证失败;
(4)每次challenge不同,所以replay attack无效。
9 设计好注册流程
由于登录时服务器和用户共享个第三方无法知道的秘密(密码),因此简单的设计就能保证很高的安全性。难点在于注册阶段,因为要保证用户设置的密码(包括哈希值,包括加盐哈希值)不在网络上传输到服务器,这只能通过https或者短信注册来保证安全了,当然这2个方法本质上还是"服务器和用户共享个第三方无法知道的秘密",前者通过非对称加密的公钥私钥作秘密,后者通过网络黑客无法截获(手机没中病毒)的动态密码作秘密。