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

相关推荐
abcnull1 小时前
用javaparser做精准测试
java·ast·静态代码分析·精准测试·javaparser
叶小鸡1 小时前
Java 篇-项目实战-苍穹外卖-笔记汇总
java·开发语言·笔记
AI人工智能+电脑小能手2 小时前
【大白话说Java面试题】【Java基础篇】第22题:HashMap 和 HashSet 有哪些区别
java·开发语言·哈希算法·散列表·hash
juniperhan2 小时前
Flink 系列第21篇:Flink SQL 函数与 UDF 全解读:类型推导、开发要点与 Module 扩展
java·大数据·数据仓库·分布式·sql·flink
ID_180079054732 小时前
Python 实现亚马逊商品详情 API 数据准确性校验(极简可用 + JSON 参考)
java·python·json
c++之路2 小时前
C++23概述
java·c++·c++23
专注API从业者3 小时前
Open Claw 京东商品监控选品实战:一键抓取、实时监控、高效选品
java·服务器·数据库
摇滚侠3 小时前
DBeaver 导入数据库 导入 SQL 文件 MySQL 备份恢复
java·数据库·mysql
古城小栈3 小时前
从 cargo-whero 库中,找到提升 rust 的契机
开发语言·后端·rust
keep one's resolveY4 小时前
SpringBoot实现重试机制的四种方案
java·spring boot·后端