短信身份验证的安全风险
涉及到的安全风险
账户接管
这个是短信身份验证最严重的安全风险,攻击者可以窃取任意用户的账户,甚至是事先不知道用户的手机号码
用户模拟
与上面的类似,但是这个的风险取决于具体的服务。通常,如果可以进行模拟,由于确认机制相同,因此也有可能窃取已注册的帐户。
短信轰炸
短信轰炸可以针对客户或任何其他人。易受攻击的Web应用程序的身份验证界面用于发送消息。对于Web服务本身,轰炸可能导致客户忠诚度和声誉受损。
资源枯竭
这里是指,web接口为了发送短信,需要连接到短信服务的提供商,而后者会对每条消息进行收费,因此,短信轰炸期间,短信验证码接口的账户余额可被消耗殆尽。
测试人员该如何寻找
验证码发送次数限制
这种机质可能会引起用户无法正常登陆,或者无法完成身份验证。
验证码发送次数限制绕过
- 例如发送一定数量的验证码址后,这里假定10次,提示验证码发送次数上限,但是点击发送还是可以继续发送验证码。而且后续发送的验证码和第十的验证码一样(这里感谢manba师傅在某次分享中提到的思路)
- 针对发送次数前端验证,可以修改前端进行绕过。
- 针对发送次数服务端验证,可以尝试在手机号码后面加上空格来进行绕过。
错误次数限制
这个是短信验证码爆破的最常见的安全风险,目前大多数短信验证码都是4-6位纯数字,最多的请求次数位100万,这针对于现代web服务来说并不算多。
针对错误次数限制绕过
- 针对错误次数在cookie里面进行限制,我们可以尝试删除cookie中的某个参数,达到绕过错误次数限制
- 针对错误次数前端验证,可以修改前端错误次数来进行绕过。
- 针对错误次数服务端验证,可以尝试在手机号码后面加上空格来进行绕过。
验证码生效时间限制
在某些时候,错误次数不受限制,但是验证码生效时间很短,比如三分钟生效时间,三分钟内发送100万个请求还是很难的。但是这里验证码生效时间在代码实现上根本没有限制。因为应用程序在发送验证码的时候发送了相同的验证码
显然,开发人员认为,如果没有输入之前的验证码,那么验证码就还算是安全的,可以不用再次生成。因此我们可以在2.5到3分钟之间再次发送请求,接受验证码,即可继续爆破。
相同的验证码用于不同的动作
比如注册用户处的验证码次数不受限制,而且他的验证码可以用来进行另一项操作,比如用户登陆。我们可以先在用户登陆处让应用程序发送一个验证码,然后给注册用户接受验证码的api处发送验证码,当验证码正确的时候,程序会返回“该用户已注册”,然后我们在使用此验证码进行登陆,来入侵任何用户的账户。
不安全的随机数
验证码本身必须是随机的不可预测的。如果验证码可预测(例如取决于 Unix时间的当前秒 )则任何用户都可以被入侵
我们发现的错误之一是,导致此漏洞的原因不在于验证码,而在于发送验证码时候会给每个验证码分配一个全局标识符,当给任何用户发送验证码的时候该标识符都会递增。
当用户发送验证码进行验证时候,以下的json请求就会发送到服务器
{"code":"1111","verification_code_id":6717620}
我们则可以尝试登录或注册的其他用户,然后发送不正确的确认代码获取到verification_code_id
值,然后将当前值递增并且发送验证请求。从而阻止其他用户并导致拒绝服务
用户封锁
前面描述的漏洞和相应的攻击是Dos攻击的特例
如果在超出错误次数限制或者发送验证码次数时阻止了用户帐户,则可能会大量拒绝服务:攻击者可以简单地对每个客户端进行几次不成功的身份验证尝试,从而阻止所有帐户。当然,为此,他需要知道他们的电话号码或登录名。
短信轰炸
短信发送次数显示限制不仅应限制使用单个电话号码登录的尝试次数,还应限制对整个应用程序的请求次数,因为攻击者可能尝试不对特定用户执行洪水攻击,而是大规模执行,以破坏服务本身(触发DoS或耗尽资金)。
这里会涉及到两种类型,只针对某一用户发送大量的验证码;还有一种是针对大量用户发送验证码。(国内大部分都是不收取此类漏洞的)
短信嗅探
通过短信发送验证码是不安全的,拦截方式有很多种。虽然通常这些都不是web服务本身的弱点引起的,但是在开发时有必要考虑此类攻击的风险。
推荐防御方式
- 使用6位的确认码,甚至可以加上字母
- 限制来自一个IP地址的身份验证尝试的次数和频率
- 考虑当前会话中的尝试次数和电话号码的总数
- 几次尝试失败后,请勿阻止用户帐户
- 对于每次登录尝试,生成一个新的不可预测的唯一标识符
- 使用单独的验证码来确认每个操作
- 不要使用可预测的标识符和确认码
- 对于高度敏感的操作,请勿使用SMS确认,执行适当的2FA或至少推送通知或呼叫。
我也在想能不能使用多因素身份认证。针对是否在常用地址,是否是常用的登陆ip,甚至是用户登陆绑定mac地址之类的。我记得社区有篇文章是关于多因素身份认证的讨论,但是我忘了收藏找不到了。