一、前置知识
短信炸弹攻击,就是通过把发送短信验证码的报文截获后进行重放造成的攻击。
威胁描述:
如果短信炸弹攻击成功,攻击者可以向该手机号一直不停的发送短信,不但因短信过多发送造成经济损失,甚至会使短信系统崩溃,无法正常提供服务。
涉及功能点:
任何涉及短信验证码发送的功能点,如用户注册、登录、转账等功能。
二、修复方案
- 前端控制,通过图形验证码的验证,如果验证不通过则不允许发送短信;
- 其次为防止类似httpclient工具直接请求没有session的情况,进行session有无判断,如果没有session信息则不允许发送短信;
- 除此之外,再从session、ip、手机号、客户号四个方面请求频率和单位时间请求次数两个角度进行限制,防止短信炸弹,具体如下:
1)session:
a.同一sessionId两次的请求时间间隔不应小于设定值(建议请求时间间隔为60s);
b.同一sessionId的单位时间请求次数不应大于设定值(建议10分钟时间内请求次数不能超过8次);
2)ip:
同一ip单位时间请求次数不应大于设定值(考虑到局域网问题,建议只限定10分钟时间内请求次数不能超过200次);
3)手机号:
a.同一手机号两次的请求时间间隔不应小于设定值(建议请求时间间隔为60s);
b.同一手机号的单位时间请求次数不应大于设定值(建议10分钟时间内请求次数不能超过5次);
4)客户号(针对如个网跳转注册直销等已知客户号的场景):
a.同一客户号两次的请求时间间隔不应小于设定值(建议请求时间间隔为60s);
b.同一客户号的单位时间请求次数不应大于设定值(建议10分钟时间内请求次数不能超过5次);
三、代码参考
安全开发实例:
-
通过session id防护:
#!java String sessionId = session.getId(); //判断同一sessionId请求时间间隔是否小于设定间隔,防止恶意攻击 Long preReqTime4Session = reqTimeMap4Session.get(sessionId); //上次请求时间 Long curReqTime4Session = System.currentTimeMillis(); //本次请求时间 AtomicInteger errorTimes4Session = reqErrorMap4Session.get(sessionId); //频繁调用累计次数 if(preReqTime4Session!=null) { //频率校验 if(curReqTime4Session-preReqTime4Session < refuseInterval) { log.error("session_attack: " + sessionId + "===curReqTime-preReqTime < refuseInterval=="); isError = true; } else { //总次数校验 if(errorTimes4Session != null && errorTimes4Session.get() >= sessionTimes) { log.error("session_attack: " + sessionId + "===errorTimes==" + errorTimes4Session); isError = true; } } } else { if(errorTimes4Session != null) { reqErrorMap4Session.remove(sessionId); } }
-
通过IP防护:
#!java String ipAddress = getIp(context); //判断同一IP请求时间间隔是否小于设定间隔,防止恶意攻击 Long preReqTime = reqTimeMap.get(ipAddress); //上次请求时间 Long curReqTime = System.currentTimeMillis(); //本次请求时间 AtomicInteger errorTimes = reqErrorMap.get(ipAddress); //频繁调用累计次数 if(preReqTime!=null) { //次数校验 if(errorTimes != null && errorTimes.get() >= ipTimes) { log.error("ip_attack: " + ipAddress + "===errorTimes==" + errorTimes); isError = true; } } else { if(errorTimes != null) { reqErrorMap.remove(ipAddress); } }
-
通过手机号防护:
#!java Long preReqTime4Phone = reqTimeMap4Phone.get(mobilePhone); //上次请求时间 Long curReqTime4Phone = System.currentTimeMillis(); //本次请求时间 AtomicInteger errorTimes4Phone = reqErrorMap4Phone.get(mobilePhone); //频繁调用累计次数 if(preReqTime4Phone!=null) { //频率校验 if(curReqTime4Phone-preReqTime4Phone < refuseInterval) { log.error("phone_attack: " + mobilePhone + "===curReqTime-preReqTime < refuseInterval=="); isError = true; } else { //次数校验 if(errorTimes4Phone != null && errorTimes4Phone.get() >= mobileTimes) { log.error("phone_attack: " + mobilePhone + "===errorTimes==" + errorTimes4Phone); isError = true; } } } else { if(errorTimes4Phone != null) { reqErrorMap4Phone.remove(mobilePhone); } }
-
通过客户号防护:
#!java Long preReqTime4CifNo = reqTimeMap4CifNo.get(cifNo4TokenImg); //上次请求时间 Long curReqTime4CifNo = System.currentTimeMillis(); //本次请求时间 AtomicInteger errorTimes4CifNo = reqErrorMap4CifNo.get(cifNo4TokenImg); //频繁调用累计次数 if(preReqTime4CifNo!=null) { //频率校验 if(curReqTime4CifNo-preReqTime4CifNo < refuseInterval) { log.error("CifNo_attack: " + cifNo4TokenImg + "===curReqTime-preReqTime < refuseInterval=="); isError = true; } else { //次数校验 if(errorTimes4CifNo != null && errorTimes4CifNo.get() >= cifNoTimes) { log.error("CifNo_attack: " + cifNo4TokenImg + "===errorTimes==" + errorTimes4CifNo); isError = true; } } } else { if(errorTimes4CifNo != null) { reqErrorMap4CifNo.remove(cifNo4TokenImg); } }
关注公众号,一起分享实用安全技术,关注安全最新事件,记录工作常见问题,吐槽生活真心操蛋。