使用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呢?

相关推荐
q***98524 分钟前
VS Code 中如何运行Java SpringBoot的项目
java·开发语言·spring boot
流水不腐5186 分钟前
若依系统集成kafka
后端
allbs9 分钟前
spring boot项目excel导出功能封装——3.图表导出
spring boot·后端·excel
帧栈14 分钟前
开发避坑指南(72):HttpHeaders 的add()方法和set()方法有什么区别?
java·spring·http
unclecss28 分钟前
把 Spring Boot 的启动时间从 3 秒打到 30 毫秒,内存砍掉 80%,让 Java 在 Serverless 时代横着走
java·jvm·spring boot·serverless·graalvm
tuokuac33 分钟前
@PathVariable与@RequestParam
java·spring
Logan Lie34 分钟前
Web服务监听地址的取舍:0.0.0.0 vs 127.0.0.1
运维·后端
q***160839 分钟前
Tomcat的server.xml配置详解
xml·java·tomcat
程序员西西40 分钟前
SpringBoot整合Apache Spark实现一个简单的数据分析功能
java·后端
n***840740 分钟前
Tomcat 乱码问题彻底解决
java·tomcat