发表于: 2018-09-10 23:40:38

1 470


今天完成的内容:

一、了解短信通道和邮箱通道的防攻击策略

1、短信通道防攻击策略

a、前端增加图文验证码

在获取短信验证码前增加图文验证码是较为常用的方法。攻击者一般是采用自动化攻击,增加图文验证码后,攻击者要对验证进行识别验证成功后才能进行模拟用户发送请求,这一步需要在页面中进行,无法采用自动化攻击。第一种攻击基本上失效,同时会增加第二种的攻击成本(有可能采用人工打码方式进行验证)选择验证码时既要考虑用户操作过程的流畅度,又应该考虑到安全度。


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

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


c、对IP进行限制

对单IP最大发送量进行限制,可以有效防止单一IP下多手机号被刷的问题。最大发送量限制是防止恶意攻击者同IP下不同手机号进行刷短信验证码行为。根据平台实际情况设计一个短信最大发送量的阀值,超过阀值将不予返回短信。


d、对注册流程进行限定

一般来讲常被攻击的地方是注册页面,一般是从两方面进行触发流程的限定。

第一种,可以从前端写入指令,只允许在官网主页跳转入注册页面;

第二种方法是对注册流程进行分步,先进行账户密码设置,设置成功后才可以再进行下一步的短信验证。

因为增加前置条件,增加攻击难度两种方法都是能有效防止自动化攻击,需要注意的是两种方法对用户体验或多或少的影响,产品经理需要结合自身平台特点选择。


e、对发送者进行唯一性识别

为了防止恶意攻击者通过修改传向服务器各项参数,造成多IP多手机号刷短信验证码的行为,所以后台应对前台传过来的参数进行验证。方法一般是用token作为唯一性识别验证,后台写一个算法将token注入到前端,然后前端可以通过相应的规则获取到token,在发送短信验证请求接口数据时带上token,在后端对token进行验证,验证通过才能正常将短信发送。


目前来说,d方案的对流程依赖较高。e方案有些复杂。所以通常采取a、b、c结合的方式。


这次我只是简单实现了下a方式,涉及到前端,调试过程中有些复杂。


前端页面代码:

<!--注意isELIgnored是选择EL表达式是否输出-->
<%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8" import="java.util.*" isELIgnored="false" %>
<html>
<head>
   <title>绑定/修改手机号</title>
   <script type="text/javascript">
       /**
        * 刷新验证码
        */
       function reloadCode() {
           var time = new Date().getTime();
           document.getElementById("imgCode").src = "<%=request.getContextPath() %>/verifyCode?d=" + time;
       }

       function checkLoginNoNull() {
           if (document.getElementById("verifycode").value == "") {
               alert("验证码不能为空!请重新输入!");
           }else{
               document.getElementById("form1").submit();
           }
       }
   </script>
</head>
<body>
<h2 align="center">绑定/修改手机号</h2>
<form action="${pageContext.request.contextPath}/u/bindPhone" id="form1" method="post" align="center">
   <table align="center" width="600">
       <tr>
           <td align="right"><font color="red">*</font><strong>手机号码:</strong></td>
           <td align="left"><input type="text" name="telephone" style="background-color: deepskyblue">
               ${map.warning}</td>
       </tr>
       <tr>
           <td align="right"><img src="<%=request.getContextPath()%>/verifyCode" id="imgCode"
                                  alt="看不清楚?请点击刷新验证码" onclick="javascript:reloadCode();"
                                  class="yzm-img"/></td>
           <td align="left"><input type="text" name="imageCode" id="verifycode" style="background-color: deepskyblue">
               ${map.error}</td>
       </tr>
   </table>
   <div align="center"><input type="button" value="发送验证码" onclick="javascript:checkLoginNoNull();"></div>

</form>
<div align="center"><button type="button"><a href="${pageContext.request.contextPath}/u/showInfo">
   放弃更改</a></button></div>
</body>
</html>

前端效果:

实现了点击图片随即更新验证码的功能。


关于验证码的生成方式,则是访问了controller的/verifyCode接口:

@RequestMapping("/verifyCode")
public void VerifyCode(HttpServletRequest request, HttpServletResponse response) {

   // 创建一个宽100,高50,且不带透明色的image对象 100 50
   BufferedImage bi = new BufferedImage(100, 40, BufferedImage.TYPE_INT_RGB);
   Graphics g = bi.getGraphics();
   //RGB色彩
   Color c = new Color(200, 150, 255);
   // 框中的背景色
   g.setColor(c);
   // 颜色填充像素
   g.fillRect(0, 0, 100, 40);

   // 定义验证码字符数组
   char[] ch = "ABCDEFGHIJKLMNPQRSTUVWXYZ0123456798".toCharArray();
   Random r = new Random();
   int len = ch.length;
   int index;
   StringBuffer sb = new StringBuffer();
   // 取出四个数字
   for (int i = 0; i < 4; i++) {
       // 循环四次随机取长度定义为索引
       index = r.nextInt(len);
       g.setColor(new Color(r.nextInt(88), r.nextInt(188), r.nextInt(255)));
       Font font = new Font("Times New Roman", Font.ITALIC, 18);
       g.setFont(font);
       g.drawString(ch[index] + "", (i * 18) + 10, 30);
       sb.append(ch[index]);
   }
   //放入Session中
   request.getSession().setAttribute("piccode", sb.toString());
   try {
       ImageIO.write(bi, "JPG", response.getOutputStream());
   } catch (IOException e) {
       e.printStackTrace();
   }
}


关于验证方式,这次我尝试在前端写了判空机制。如果填写为空,则不触发事件提交表单。但是输入后验证还是更改了下。就是加了个对于图片验证码的比较判断。验证码的储存和传递都是利用了session。


关于b方案和c方案。解决的思路目前看有两种。


思路一:建立一张数据表,存储id、手机号、验证码、ip、发送时间等信息。然后通过查询记录条数,实现限制单个手机号和ip当天注册次数的目的。

优点:能够达到目的,而且能够记录和统计一些注册信息。

缺点:无法实现同时计次计时。需要前台配合计时。且需要增加数据表和对应的各层。


思路二:在注册过程中,controller层直接获取数据生成验证码后,多记录两个参数,时间和次数。把时间、次数、手机号、验证码都存入缓存。

每次重新发送,即从判断中取出对应数据判断。主要是时间是否达到间隔以及次数是否到达上限。以此限制手机注册次数。

优点:工作量比较小。

缺点:比较依赖缓存。


感觉思路二比思路一好点?


二、邮箱的防冲击。

邮箱的防冲击策略基本借鉴短信。


三、关于缩略图

1.缩略图的作用是调取图片的时候是直接处理过的经过缩减的图片,方便在一些不方便使用img标签中将其进行指定比例的缩减。

阿里云的方法是在图片的url的加上一串参数

?x-oss-process=image/resize,w_150,h_180

比如这个就是将原图缩减为宽150,高180

原来的是,可以看到直接就在原图的基础上缩略了。

所以如果想要得到一个缩略过的图,可以在数据库里面提取的url后面加上这个参数就可以了。


四、查看关于把配置写到spring的方法。

还是思路问题,我原先采用属性文件,然后工具类直接读取属性文件得到参数。


如果写到spring配置文件里,难道是指把工具类注册为bean?然后通过属性注入写入bean的参数?


明天的计划:

1、解决参数写入spring的问题。

2、了解图片迁移。


遇到的困难:到了现在的阶段,基本是各种思路和方案的思考和选择。今天关于图片验证码,因为对于前端不了解,费了挺多时间。感觉很多验证前端做着比后端容易的多。



返回列表 返回列表
评论

    分享到