背景

前几天项目上需要对一个正常登陆接口,以及忘记密码的接口进行防爆破处理,这里我用nginx,redis,以及前端的一些简单的图形拖动来做一个简单的安全机制,可能有不完善的地方,大家可以提出来意见。

技术分析

其实一个接口是无法完全避免接口爆破的,区分人和机器或许可以使用谷歌的图片验证机制,但是我们一般简单项目没必要做那么复杂的,只需要确保不正常的访问频率不会爆破出我们的用户信息,以及让我们机器的处理流量保存在可控范围即可。
实现的效果有下面这几点:

  1. 验证码只能60s获取一次 并且3小时内只能获取三次,超过次数提升获取频繁,稍后再试。
  2. 正常登录1小时内失败6次账号自动锁定,1小时之后自动解锁。
  3. 获取验证码无论输入的账号存在不存在均显示发送成功,但是实际不存在的账号不会正常发送。
    4.登录失败,账号不存在密码错误不再提示账号不存在等等,而是统一显示账号或密码错误。5.忘记密码前端部分增加滑动校验,60倒计时无法点击发送验证码。前后端共同校验。6.技术限制系统此接口的访问频率。

前端部分

前端部分可以在这个地址看看这几个简单的组件,这次我们就使用最简单的,滑动拖动即可。

           <drag-verifyref="dragVerify":width="width":height="height"text="请按住滑块拖动"successText="验证通过":isPassing.sync="isPassing"background="#ccc"completedBg="rgb(105, 231, 251)"handlerIcon="el-icon-d-arrow-right"successIcon="el-icon-circle-check"@passcallback="passcallback"></drag-verify>

用户滑动之后需要加上60s倒计时,这块我们使用定时器实现即可,以及邮箱和手机号的正确性校验,不正确则弹窗提示。

      this.countDown = 60;timer = setInterval(() => {if (this.countDown - 1 >= 0) {this.countDown -= 1;} else {clearInterval(timer);timer = null;}}, 1000);
<el-button disabled type="text" v-show="time > 0"> {{ time > 0 ? `${time}` : "" }} s之后重试</el-button>

验证邮箱手机号可以使用正则校验进行。

      mobileReg = /^1\d{10}$/;emailReg = /^([A-Za-z0-9_\-\.\u4e00-\u9fa5])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,8})$/;

前端大体思路就是,进行滑块验证,拖到右边之后,60s之内无法操作,60s到期之后自动复原,
显示倒计时时间。这个只能防止用户在页面上多次点击,造成一个验证的假象,如果直接对后端接口爆破,则无法避免。

后端

这是大概的流程图,图中还有些细节问题下面慢慢讲解。

这块本来我想用java或者kotlin写,但是历史项目用go写的,重写的话还有其他一些改动,所以继续使用golang完成这部分逻辑。

先定义一个结构体,然后我们来分析下需要哪些字段来实现我们的业务。
我们需要一个首次登陆时间,最后一次登陆时间,和总的登录次数足以判断:

  1. 验证码间隔
  2. 登陆失败次数
  3. 距离第一次登陆失败次数间隔
type CommonLogin struct {CreateTime time.TimeLastTime   time.TimeTimes      uint8
}

正常登陆的前置校验

// 登录的前置校验
func beforeCommonLoginValid(key string, r *redis.Client, field string) (bool, error) {// redis中是否存在账号result, err := r.HExists(field, key).Result()if err != nil {fmt.Printf("从redis中获取用户账户失败,账户为: %s", key)return false, err}if result {login := &CommonLogin{}// 存在账号 说明之前登录失败过 且自从上次失败未登录成功过commonLogin, err := r.HGet(field, key).Result()if err != nil {return false, err}json.Unmarshal([]byte(commonLogin), login)if login.Times < 6 {return true, nil}// 是否在1小时内失败了6次if login.Times >= 6 {// 否if time.Now().Sub(login.CreateTime) > time.Hour*1 {// 连续输错6次时长大于1小时 解锁r.HDel(field, key)return true, nil} else {fmt.Printf("用户%s于1小时之内连续登录失败6次,账号锁定,1小时后重试。", key)return false, nil}}}// redis中不存在重试记录return true, nil
}

在所有的登录判断的出口,调用此方法即可,例如用户名密码错误,acl校验未通过等等。

忘记密码的登录前置校验

其实原理差不多,唯一的区别就是多了一个获取验证码时间间隔校验。

 func beforeForgotPasswordValid(key string, r *redis.Client, field string) (bool, error) {// redis中是否存在账号result, err := r.HExists(field, key).Result()if err != nil {fmt.Printf("从redis中获取用户账户失败,账户为: %s", key)return false, err}login := &CommonLogin{}// 账号存在if result {commonLogin, err := r.HGet(field, key).Result()if err != nil {return false, err}json.Unmarshal([]byte(commonLogin), login)// 获取验证码间隔时长不能小于60sif time.Now().Sub(login.LastTime) < time.Second*60 {fmt.Printf("用户获取验证码间隔小于60s")return false, nil}if login.Times < 3 {return true, nil}// 是否在1小时内获取了3次if login.Times >= 3 {// 否if time.Now().Sub(login.CreateTime) > time.Hour*3 {// 连续输错6次时长大于1小时 解锁r.HDel(field, key)return true, nil} else {fmt.Printf("用户%s于3小时之内连续获取验证码3次,账号锁定,3小时后重试。", key)return false, nil}}}return true, nil
}

忘记密码的后置校验

 // 更新获取验证码的时间
func afterForgotPasswordValid(key string, r *redis.Client, field string) {login := &CommonLogin{}commonLogin, _ := r.HGet(field, key).Result()json.Unmarshal([]byte(commonLogin), login)// 验证码发送成功result, _ := r.HExists(field, key).Result()if result {login.Times = login.Times + 1login.LastTime = time.Now()data, _ := json.Marshal(login)r.HSet(field, key, data)} else {login.Times = 1login.LastTime = time.Now()login.CreateTime = login.LastTimedata, _ := json.Marshal(login)r.HSet(field, key, data)}
}

使用nginx进行接口访问频率限制

nginx是一个非常强大的中间价,在安全方面,我们可以用它来限制来自于同一机器的访问频率,可以做黑名单功能等等,当然有人会说ip代{过}{滤}理池之类的,我们此次演示的只是简单demo,恶意攻击当然需要专业防护了。
具体google一下,看这两篇官方文档。

https://docs.nginx.com/nginx/admin-guide/security-controls/controlling-access-proxied-http

https://www.nginx.com/blog/rate-limiting-nginx/
具体的配置其实很简单了。
限制远程同ip访问频率。

limit_req_zone $binary_remote_addr zone=perip:10m rate=1r/s;

解释下这段配置的参数:
$binary_remote_addr 表示通过remoteaddr这个标识来做限制,“binary”的目的是缩写内存占用量,是限制同一客户端ip地址
zone=one:10m表示生成一个大小为10M,名字为one的内存区域,用来存储访问的频次信息
rate=1r/s表示允许相同标识的客户端的访问频次,这里限制的是每秒1次,还可以有比如30r/m的

location ^~ /api/xxx {limit_req zone=perip nodelay;limit_req_status 503;proxy_pass http://正确地址;}

上面配置意思就是超过频率返回503,服务不可用。
使用jmeter进行压力测试:1s 10个请求,我们预期只有1个请求成功,其他的返回503.

核心逻辑其实就是上面这些,源码不贴出来了,有不懂的再讨论吧。

后台登陆防刷、防爆破以及正常的登录校验相关推荐

  1. 基于springboot2.x+redis的接口防刷(防DOSS攻击)

    参考文章:https://blog.csdn.net/qq_17635843/article/details/78990881 自定义一个拦截器集成HandlerInterceptorAdapter里 ...

  2. 短信接口防刷防轰炸解决方案Java接入教程- 企业短信防火墙+ 【中昱维信】短信验证码

    企业短信防火墙[新昕科技]+短信验证码[中昱维信]Java应用实例 一.企业短信防火墙的实现 1.1 简介 1.2 第一步:获取防火墙帐号密钥 1.3 第二步:下载防火墙服务器 1.4 第三步:业务系 ...

  3. 短信验证码/邮箱验证码的发送及防刷校验

    一.发送短信验证码及接口防刷 1.前台注册或登录页面调用的后端接口(防刷,并利用openfeign调用另一个服务发短信): @ResponseBody@GetMapping("/sms/se ...

  4. java实现发送短信验证码、短信验证码防刷校验-49

    一:认证服务环境搭建 1.新建gulimail-auth-server 2.整合相关依赖 <!--引入commom依赖--><dependency><groupId> ...

  5. 优雅的接口防刷处理方案

    点击上方"Java基基",选择"设为星标" 做积极的人,而不是积极废人! 每天 14:00 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | Java ...

  6. java发送QQ邮箱验证码实现登录注册、邮箱验证码防刷校验

    文章目录 一:前台功能实现 1.1 页面编写 1.2 发送验证码--sendEmailCode 1.2.1 远程调用发送接口 1.2.1 接口防刷校验--60s内只能发送一次 二:获取QQ邮箱授权码 ...

  7. 产品防护:5种常见的短信验证码防刷策略

    短信验证码作为重要的身份验证工具,因其操作简便.安全性高.时效性强等优点已被开发人员广泛使用.但因其获取便利.限制较少容易被不法分子利用进行短信轰炸,恶意刷掉大量短信费用,给公司或个人造成大量的金钱损 ...

  8. 一个注解搞定接口防刷!还有谁不会?

    点击关注公众号,Java干货及时送达 说明:使用了注解的方式进行对接口防刷的功能,非常高大上,本文章仅供参考 一,技术要点:springboot的基本知识,redis基本操作, 首先是写一个注解类: ...

  9. 一个注解搞定 SpringBoot 接口防刷,还有谁不会?

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 作者:CS打赢你 blog.csdn.net/weixin ...

最新文章

  1. java 实体类包含list 怎么取值_2019 最新 500 道 Java 面试题
  2. POJ-2942:吃糖果
  3. 用户和组相关配置文件
  4. oracle 常见操作
  5. 开发pc页面_干货分享:2020年Web前端开发学习路线图
  6. centos7安装MySql(yum方式)
  7. 深入理解 Spring 事务原理
  8. 平方和误差函数--代价函数(机器学习)
  9. HDFS的StartupProgress启动跟踪分析
  10. 实战剖析:13步设计出一个ITSM系统
  11. 苹果计算机如何显示错误,科普电脑打开苹果手机视频教程及Apple ID验证失败发生未知错误怎么解决...
  12. 反函数求导:自然对数 ln是怎么得到的;为什么自然对数的导数是 1/ x;arcsin 和 arccos 的导数求算
  13. 简单通用QQ/微信跳转浏览器打开代码
  14. 网络安全自学入门:(超详细)从入门到精通学习路线规划,学完即可就业
  15. google翻译不能用后chrome浏览器如何翻译网页
  16. 关于git中,两个branch自动同步的问题和解决
  17. windows10 宽带或者无线连接校园网都出错,如何解决
  18. 条形码入门指南(八):二维条形码
  19. micro-app的简单学习
  20. ELMO的CAN总线H-L线之间用示波器测量图像

热门文章

  1. 停止厄运:网络才刚刚起步
  2. php 实现快钱支付功能(涉及到接口)
  3. 《三十六计》搞笑图解
  4. 行驶记录仪和道路运输车辆卫星定位系统相关标准总结
  5. 基于单片机智能盲人拐杖臂章报警系统设计(毕设课设)
  6. 一次性撤稿70篇!中国学者论文再现大规模撤稿 | 附全名单
  7. Excel函数 -名称相同序号自动递增(用于重复值排序)
  8. img和background的区别
  9. 基于matlab的短波通信信号基本样式(AM、DSB、FM、2ASK、2FSK、2PSK)
  10. c#控件弹幕效果_Android 自定义View修炼-自定义弹幕效果View