使用JWT你应该要注意Token劫持安全问题

大家好,我是小趴菜,在工作中我们经常要做的一个就是登陆功能,然后获取这个用户的token,后续请求都会带上这个token来验证用户的请求。

问题背景

我们经常使用的JWT就是其中一种,如下

typescript 复制代码
//生成Token  
public static String generateToken(Map<String, Object> payloads) {
        Map<String, Object> map = new HashMap<>(2);
        map.put("alg", "HS256");
        map.put("typ", "JWT");
        Date date = new Date(System.currentTimeMillis() + EXPIRE);
        JWTCreator.Builder jwtBuilder = JWT
                .create()
                .withHeader(map)
                .withExpiresAt(date);
        for (Map.Entry<String, Object> entry : payloads.entrySet()) {
            jwtBuilder.withClaim(entry.getKey(), entry.getValue().toString());
        }
        return jwtBuilder.sign(Algorithm.HMAC256(SECRET));
    }

//校验Token
public static Map<String, Claim> verifyToken(String token) {
    try{
        JWTVerifier verifier = JWT
                .require(Algorithm.HMAC256(SECRET))
                .build();
        DecodedJWT jwt = verifier.verify(token);
        return jwt.getClaims();
    }catch (Exception e){
        throw new GlobalException(ResponseEnums.TOKEN_VERIFY_FAIL_ERROR);
    }
}

我们会给每一个Token设置一个过期时间,前端拿到这个token以后,在之后的用户每一次请求都会带上这个Token进行校验,如果过期了或者Token格式不对,我们就不让请求通过,直接返回错误信息给前端

js 复制代码
        //从请求头中拿到token key : token
        String headerToken = request.getHeader(TokenConstant.TOKEN_HEADER);
        if (StrUtil.isBlank(headerToken)) {
            throw new GlobalException(ResponseEnums.TOKEN_IS_NULL_ERROR);
        }
        
        //解析token
        Map<String, Claim> claimMap = JwtUtil.verifyToken(headerToken);
        return true;
    }

这看上去是一件很美好的事情,因为我们解决了用户请求校验的问题,但是这个Token是存储在前端的缓存中的。当我们点击退出登陆的时候,前端也只是把缓存的这个Token给清掉,这样用户后续的请求就没有这个Token,也就会让用户去重新登陆了。这看起来是没有问题的。

但是如果你这个Token还没有过期,这时候你的Token被其他人截取了,这时候,即使你退出登陆但是这个Token一样是可以通过校验的。所以其他人还是可以拿你这个Token去请求对应的接口。这时候就会有安全问题了。那有没有解决办法呢?

解决办法

其实是有的。我们可以把这个Token保存到Redis中。每次请求的时候,判断一下Redis中有没有这个Token,有就放行,没有就返回错误信息给前端。

当用户点击退出登陆的时候,把Redis的这个Token给删除掉就行了,这样后续即使用人截取了你这个Token,由于Redis没有,那么第一步返回fasle,就可以直接返回错误信息给前端,不会去执行这个请求

思考

既然我们使用了Redis那用JWT的意义在哪呢?我们Redis也可以设置过期时间,还可以给Token续期,很多JWT做不到的事Redis都可以做到。那为什么还要使用JWT呢?

相关推荐
Chenyiax6 分钟前
从 Chat 到 Responses:OpenAI API 抽象为什么变了?
后端
MariaH7 分钟前
Koa和Express的区别
后端
MariaH13 分钟前
Koa框架的使用
后端
luckdewei1 小时前
那个用 passlib 做认证的新同事,上线第一天就把用户密码写进了日志
后端
ping某3 小时前
为什么 Nginx 明明监听了 80,转发后端时却用了 4xxxx 端口?
后端·nginx
JustHappy3 小时前
我汇总了身边朋友的经历才发现,其实第一份实习是最难找的......
前端·后端·面试
uhakadotcom3 小时前
在python 的 工程化架构中 ,什么是 薄包装器层?
后端·面试·github
唐青枫7 小时前
Java JDBC 实战指南:从 Connection 到事务和连接池
java
用户1474853079747 小时前
CodeX使用Skill生成游戏美术和音乐资源,一分钟入门
后端
假如让我当三天老蒯7 小时前
模块化:ES Module 与 CommonJS 的区别
前端·面试