你真的够努力吗?

session与短信炸弹

0x00 短信炸弹

最近的测试过程中,遇到了很多厂商的验证码业务都存在短信炸弹的情况,可以出现在注册、登录、重置密码的某个步骤中,输入手机号之后抓取获取验证码的数据包进行重放,从而达到在短时间内对同一个手机号进行短信轰炸的目的。还有一种情况是对于服务端对某一个手机进行攻击会做限制,但是可以对不同号码进行多次的攻击(即针对某一个号码段的号码进行“群发”短信)。

0x01 常见防护手法

从自己遇到的一些防御手段来介绍吧。。。。

1、增加验证码。

在输入手机号之后同时要加上验证码,两个参数同时发送到服务端,服务端首先对验证码进行识别,当验证码判断正确之后再对该手机发送验证码。

这一种防御方式依旧存在漏洞。攻击者可以使用验证码识别插件编写脚本进行识别,同时提交到服务器进行短信轰炸。这一类只是提高了攻击门槛,但是不能从根本上解决问题。

2、根据session进行判断。

用session作为唯一性识别验证,后台写一个算法将手机号与发送次数写入到session的某个值里,发送给客户端。之后用户每次请求发送短信的同时,要带上该session。其中就有包含用户当前唯一身份标识的信息。服务器每次发送验证码的时候就将该用户的发送次数加1,当达到5次或者某个上限时就不在发送短信。这一种情况在实际情况中挺常见的,但是设计也要做到仔细不然就会有很大的问题。

首先是判断逻辑。在几次测试过程中,我也遇到过类似的情况。直接重放数据包,只能发送1个短信就会提示已发送过了。但是如果删除cookie就可以无限次数重放了。这是因为后台在判断cookie时没有考虑完全,忽略了当cookie 为空的情况。正确的情况应该是首先判断cookie 参数是否存在,不存在就返回到前一个界面或者提示会话已过期。当cookie参数存在的时候再判断该用户已发送过多少次,如果超出限制就提示错误,不再发送。之后会详谈

3、对手机号做出限制。

对单个手机号进行日接收次数的限制,可以防止单个手机号无限制刷短信,同时设置时间间隔可以有效。短信接收次数可以根据平台特点进行限制,一般日接受验证码次数为10次左右;同一号码发送时间间隔通常为60秒或者更长,前后台应保持一致,避免出现只前端做倒计时限制,后台未做限制这种低级错误。

4、对IP做出限制。

对单IP最大发送量进行限制,可以一定程度防止单一IP下对多个手机号进行炸弹攻击的问题。最大发送量限制是防止恶意攻击者同IP下不同手机号进行刷短信验证码行为。根据平台实际情况设计一个短信最大发送量的上限,超过上限则不发送短信。但是这种情况攻击者可以使用代理工具绕过限制。

0x02 session

先总结一下自己对于session的学习总结。

因为http本身是无连接的超文本传输协议,为了让http会话可以保持某种会话状态,就提出cookie机制。cookie是一种将会话相关信息存储在用户本地的技术,因为存储在客户端从而导致了诸多安全问题,因此就提出了将“cookie”保存在服务器的想法,这就是session了。

当服务器接受到某个客户端发来的请求时,会首先检查这个客户端的请求里是否已包含了一个session标识 - 称为session id,如果已包含一个session id则说明以前已经为此客户端创建过session,服务器就按照session id把对应的session检索出来使用(如果检索不到,可能会新建一个)。如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id。因此作为唯一标识一个session的session id的值应该是足够随机的字符串。

对session来说,除非客户端通知服务器删除一个session(例如注销登录),否则服务器会一直保留,因为服务器根本不会有机会知道浏览器已经关闭,要实现自动删除,就是在服务端为每一个session设置一个有效期,当距离客户端上一次使用session的时间超过这个失效时间时,服务器就可以认为客户端已经停止了活动,才会把session删除以节省存储空间。当下次再使用该session-id发起请求时,因为服务器已经删除了,所以就会新建一个session并返回session-id。大部分session机制都使用会话cookie来保存session id,而关闭浏览器后这个cookie就会消失,同时也就意味着session id消失了,再次连接服务器时也就无法找到原来的session。如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的HTTP请求头,把原来的session id发送给服务器,只要服务器未主动删除session的话打开浏览器仍然能够找到原来的session。

0x03 session与短信炸弹

接下来就详谈第二点session与短信炸弹的关系

实现的部分代码如下:

@RequestMapping(value = "sendMessage",method = RequestMethod.GET)
public Object sendMessage(final HttpServletRequest request){
    // 如果不存在 session 会话,则创建一个 session 对象
    HttpSession session = request.getSession(false);
    String phone=session.getParameter("phone");
    String times=session.getParameter("times");
    final times_permit = 5;

    if (session ==null) {
        //session为空的处理
    }
    if (phone == null ) {
        //手机号为空的处理
    }
    
    if (times > times_permit) {
        //次数超出限制的处理
    }

    String checkCode=GenerateRandomCode.createRandomNumber(6);
    httpSession.setAttribute("checkCode",checkCode);
    CheckCodeMessage checkCodeMessage=new CheckCodeMessage(phone,checkCode);
    try {
        HttpSender.batchSend(checkCodeMessage);
        //TimerTask实现5分钟后从session中删除checkCode
        final Timer timer=new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                httpSession.removeAttribute("checkCode");//时间到,清除验证码
                //System.out.println("checkCode删除成功");
                timer.cancel();
            }
        },5*60*1000);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return "redirect:/index.jsp";
}

0x04 后记

我觉得以上的修复方案在大多时候已经足够了。但是跟某位大佬探讨时,他提到如果攻击者每次都使用不同的sessionid去重新开始会话,这样同样可以对某个手机号进行连续轰炸,但是这样攻击已经失去了实际意义了。对于这种情况的防御就是使用redius或者其余数据库来存储一个手机号和其对应的发送次数,但是对于效率和成本来说不一定划算,要视不同公司不同的业务情况而定,这里不做讨论。

posted @ 2018-09-05 22:07  陈一生  阅读(1010)  评论(0编辑  收藏  举报