登陆接口的设计+springboot防暴力破解

安全——登陆接口的设计

没有绝对的安全,只的一步一步的防护

登陆是系统的门户接口,也是最容易被访问的接口。你写的是合格的吗,还是只是实现了个查询。

一、相关库表的设计

1、用户的基本信息和用户账号信息最好没有放在一个表;

2、有没有三方登陆的需求,有的话;第三方的信息最好在一个表;

3、密码加密是肯定的,那加盐了吗,账号信息表中放一个salt吧;

4、做上登陆记录Log表,也可以记录ip可以做异地提醒;

二、你的友好提示可能存在安全问题

1、账号不存在?表示你做了一个全表的账号查询。
2、密码错误?表示我的账号是对的了?那我试试这个密码?

* 账号或密码错误。这是可取的。

三、做一个防暴力破解吧

传统用户名,密码登陆
例子:登陆接口,一分钟内出错超过3次,账号封锁3分钟,并向用户手机发送验证和提醒。具体业务逻辑可以自定义;

实现:springboot的aop+redis

aop的两个方法:

@AfterReturning :后置——接口方法执行完
@AfterThrowing:存在异常——接口方法执行存在异常

基本逻辑:账号失败一次,就把账号做为key,vaue为 0,time=过期时间放到redis里;失败一次+1;成功:看看redis里有没有这个key,有就删除;

redis.setString(key:用户名或账号,value: 次数,time:(过期时间))

核心代码:

@AfterReturning(returning = "ret", pointcut = "countPoint()")// returning的值和doAfterReturning的参数名一致
public void doAfterReturning(Object ret) throws Throwable {
    ObjectMapper objectMapper = new ObjectMapper();
    // ResponseVO responseVO = objectMapper.convertValue(ret, ResponseVO.class);
    String s = redisUtils.get(redisKey);
    if (s != null) {
        redisUtils.del(redisKey);
    }
}
  @AfterThrowing(throwing = "ex", pointcut = "countPoint()")
public void afterThrowing(Exception ex) {
    String s = redisUtils.get(redisKey);
    if (null == s) {
        redisUtils.set(redisKey, "1", defaultTimeOut);
    } else {
        Integer i = Integer.parseInt(s) + 1;
        if (i < count) {//小于设定次数
            long ttl = redisUtils.ttl(redisKey);
            redisUtils.set(redisKey, i.toString(), ttl);
        }
        if (i == count) {//符合设定值
            redisUtils.set(redisKey, i.toString(), timeOut);
            throw new EchoException("请求锁定," + timeOut + "秒后再做尝试。");
        }
    }

}

完整代码

1、自定义注解

/**
 * @Description: 多次接口尝试进行账户封锁
 * @Author: HuangJiangMin
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodResponseException {
    /**
     * 失敗次数
     */
    int exceptionCount() default 5;

    /**
     * 限制时间 (秒)
     */
    long redisExpired() default 60;

}

2、AOP

/**
 * @Description:多次接口尝试进行账户封锁
 * @Author:HuangJiangMin
 */

@Aspect
@Component
public class ResponseExceptionAspect {
    @Autowired
    private RedisUtils redisUtils;

    private String redisKey;
    private int count;
    private long timeOut;
    private long defaultTimeOut = 60;

    @Pointcut("@annotation(scirichon.echo.art.infrastructure.annotation.MethodResponseException)")
    private void countPoint() {

    }

    @Before("countPoint()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {

        // 接收到请求,记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String methodUrl = request.getRequestURL().toString();
        /**
         * 获取注解自定义参数
         */
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        MethodResponseException methodResponseException = method.getAnnotation(MethodResponseException.class);

        count = methodResponseException.exceptionCount();
        timeOut = methodResponseException.redisExpired();


        redisKey = RedisEnum.RESPONSE_EXCEPTION_COUNT_KEY.tacetion(methodKey);
        String s = redisUtils.get(redisKey);

        if (null != s && count == Integer.parseInt(s)) {
            throw new EchoException("请求锁定中,请稍后再做尝试。");
        }

    }

    @AfterReturning(returning = "ret", pointcut = "countPoint()")// returning的值和doAfterReturning的参数名一致
    public void doAfterReturning(Object ret) throws Throwable {
        ObjectMapper objectMapper = new ObjectMapper();
        // ResponseVO responseVO = objectMapper.convertValue(ret, ResponseVO.class);
        String s = redisUtils.get(redisKey);
        if (s != null) {
            redisUtils.del(redisKey);
        }
    }

    @AfterThrowing(throwing = "ex", pointcut = "countPoint()")
    public void afterThrowing(Exception ex) {
        String s = redisUtils.get(redisKey);
        if (null == s) {
            redisUtils.set(redisKey, "1", defaultTimeOut);
        } else {
            Integer i = Integer.parseInt(s) + 1;
            if (i < count) {//小于设定次数
                long ttl = redisUtils.ttl(redisKey);
                redisUtils.set(redisKey, i.toString(), ttl);
            }
            if (i == count) {//符合设定值
                redisUtils.set(redisKey, i.toString(), timeOut);
                throw new EchoException("请求锁定," + timeOut + "秒后再做尝试。");
            }
        }

    }

    @Around("countPoint()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object ob = pjp.proceed();// ob 为方法的返回值
        //logger.info("性能监控(耗时) : " + (System.currentTimeMillis() - startTime) + "毫秒");
        return ob;
    }
}

 

以上就用springboot实现了防暴力破解

安全只是相对的。

有人说了,我可以写个程序一直调用你的接口;让所有的用户都登陆不上。
——用CSRF可以;
又有问题了 referer可以人为变更。你要怎么处理呢。
——一个IP一分钟内访问超过多少次,就封禁可以吗(这个不一定可行)

只有层层防护。没有绝对安全

我的个人博客:
http://www.dhzi.com.cn/

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue2,ElementUI,SpringBoot,Mybatis,MySQL8.0是一组优秀的前后端技术组合。Vue2是一款流行的前端框架,具有响应式的数据绑定和组件化开发等特点,适合开发动态交互性强的单页面应用;ElementUI是一款基于Vue2的UI库,提供了一系列美观实用的组件,可快速搭建现代化的Web应用;SpringBoot是一款基于Spring框架的轻量级应用开发框架,使用简单,能够快速集成其他框架;Mybatis是一个优秀的ORM框架,能够极大地提高Java开发与SQL交互的效率,避免手写SQL语句的麻烦;MySQL8.0则是一个高性能、稳定性强的关系型数据库,使用广泛。 结合这些技术进行登陆注册系统的开发,可以使用Vue2和ElementUI实现前端页面的效果,使用SpringBoot作为后端框架,利用Mybatis对MySQL8.0数据库进行访问。具体开发过程可以分为以下几步: 1. 后端开发:使用SpringBoot框架搭建RESTful风格API接口,使用Mybatis框架访问MySQL8.0数据库,并实现用户登陆、注册以及对用户信息的增删改查等功能。 2. 前端开发:使用Vue2和ElementUI完成前端页面的搭建,包括登陆、注册、用户信息管理等页面,并使用Axios等技术与后端进行数据传输。可以使用Vuex实现数据的状态管理和共享。 3. 接口实现:在前后端开发完成后,需要将后端的API接口与前端进行对接,实现数据的交互。可以使用Postman等工具测试和调试接口。 4. 系统上线:在完成开发后,需要对系统进行测试和调试,确保系统能够稳定运行并满足用户需求后,再进行部署上线。 综上,登陆注册Vue2 ElementUI SpringBoot Mybatis MySQL8.0的开发过程相对复杂,需要前后端开发人员精细的协作和技术储备,但使用这些优秀的技术组合可以有效提高开发效率和用户体验,是一种切实可行的开发方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值