安全技术--接口幂等性设计

上一篇 <<<安全技术--Https相关知识
下一篇 >>>安全框架--SpringSecurity


幂等:无论请求多少次,数据都不会变,防止重复提交

幂等设计方案

  • 1.MVCC方案(乐观锁方式)

select * from tablename where condition=#condition# // 取出要跟新的对象,带有版本 versoin
update tableName set name=#name#,version=version+1 where version=#version#
在更新的过程中利用 version 来防止,其他操作对对象的并发更新,导致更新丢失。为了避免失败,通常需要一定的重试机制。

  • 2.悲观锁

select for update,整个执行过程中锁定该订单对应的记录。注意:这种在DB读大于写的情况下尽量少用。

  • 3.去重表

在插入数据的时候,插入去重表,利用数据库的唯一索引特性,保证唯一的逻辑。

  • 4.Token机制

业务要求:页面的数据只能被点击提交一次
发生原因:由于重复点击或者网络重发,或者 nginx 重发等情况会导致数据被重复提交
解决办法:
集群环境:采用token加redis(redis 单线程的,处理需要排队)
单JVM环境:采用token加redis或token加jvm内存
处理流程:
--数据提交前要向服务的申请token,token放到redis或jvm内存,token有有效时间
--提交后后台校验token,同时删除token
token特点:要申请,一次有效性,可以限流

纯手写互联网API接口幂等框架

    1. 接口方式保证幂等性

a、提供查询令牌查询接口
b、令牌放在请求头中提交,服务端使用AOP统一处理

    1. 表单提交保证幂等性

a、自定义注解ExtApiToken,AOP中发现此注解就生成令牌信息放到request中,页面上做令牌的隐藏
b、-令牌信息和其他数据一起以form方式提交到服务端,服务端以ExtApiIdempotent注解来做AOP统一处理

  • 3.核心代码
// 1.使用AOP环绕通知拦截所有访问(controller)
@Pointcut("execution(public * com.jarye.controller.*.*(..))")
public void rlAop() {}

// 含有ExtApiToken注解的均设置令牌信息
@Before("rlAop()")
public void before(JoinPoint point) {
    MethodSignature signature = (MethodSignature) point.getSignature();
    ExtApiToken extApiToken = signature.getMethod().getDeclaredAnnotation(ExtApiToken.class);
    if (null==extApiToken) {
        return;
    }
    // 可以放入到AOP代码 前置通知
    getRequest().setAttribute("token", redisToken.getToken());
}

// 环绕通知
@Around("rlAop()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    // 2.判断方法上是否有加ExtApiIdempotent注解
    MethodSignature methodSignature = (MethodSignature) proceedingJoinPoint.getSignature();
    ExtApiIdempotent declaredAnnotation = methodSignature.getMethod().getDeclaredAnnotation(ExtApiIdempotent.class);
    // 3.如何方法上有加上ExtApiIdempotent
    if (declaredAnnotation != null) {
        String type = declaredAnnotation.type();
        // 如何使用Token 解决幂等性
        String token = null;
        HttpServletRequest request = getRequest();
        //接口形式是放在头部,表单形式是放在body中
        if (type.equals(ConstantUtils.EXTAPIHEAD)) {
            token = request.getHeader("token");
        } else {
            token = request.getParameter("token");
        }
        if (StringUtils.isEmpty(token)) {
            return "参数错误";
        }
        // 3.接口获取对应的令牌,如果能够获取该(从redis获取令牌)令牌(将当前令牌删除掉) 就直接执行该访问的业务逻辑
        boolean isToken = redisToken.findToken(token);
        // 4.接口获取对应的令牌,如果获取不到该令牌 直接返回请勿重复提交
        if (!isToken) {
            response("请勿重复提交!");
            // 后面方法不在继续执行
            return null;
        }

    }
    // 放行
    Object proceed = proceedingJoinPoint.proceed();
    return proceed;
    
}

相关文章链接:
<<<Web常用攻击手段-XSS
<<<Web常用攻击手段-SQL注入
<<<Web常用攻击手段-Http请求防盗链
<<<Web常用攻击手段-CSRF攻击
<<<Web常用攻击手段-上传文件漏洞
<<<Web常用攻击手段-忘记密码
<<<Web常用攻击手段-其他漏洞
<<<安全技术--数据加密/认证技术
<<<安全技术--Https相关知识
<<<安全框架--SpringSecurity
<<<安全框架--JWT
<<<安全框架--OAuth2
<<<安全架构整体设计方案

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容