MST

星途 面试题库

面试题:安全认证之JWT在无状态会话中的专家难度题

在微服务架构中,多个服务都依赖JWT进行安全认证,若其中一个服务遭受重放攻击,如何基于JWT的特性在整个架构层面进行有效的防御,详细描述设计方案与关键实现点。
11.7万 热度难度
后端开发安全认证

知识考点

AI 面试

面试题答案

一键面试

设计方案

  1. 使用JWT的过期时间机制
    • 在生成JWT时,设置合理的过期时间(exp字段)。例如,对于普通的用户认证JWT,设置较短的过期时间,如15分钟。这样即使JWT被截获并尝试重放,在过期后就无法使用。
    • 各个依赖JWT认证的微服务在验证JWT时,严格检查exp字段,拒绝已过期的JWT。
  2. 引入随机数或一次性使用标识
    • 在生成JWT时,添加一个唯一的随机数(如UUID)作为自定义字段(例如nonce)。每个JWT的nonce值都是不同的。
    • 微服务端维护一个已使用nonce值的记录(可以使用缓存,如Redis)。当收到JWT进行认证时,首先检查nonce是否已经在使用记录中。如果存在,则拒绝该JWT,表明这可能是一次重放攻击;如果不存在,则将该nonce添加到使用记录中,并继续进行认证流程。
  3. 结合时间戳和滑动窗口机制
    • 在JWT中添加一个时间戳字段(例如iat,表示JWT的签发时间)。
    • 微服务端设置一个时间滑动窗口,比如5分钟。当收到JWT时,检查iat字段,若iat距离当前时间在滑动窗口内,则认为JWT是有效的,否则拒绝。这可以防止攻击者使用较旧的JWT进行重放攻击,同时也避免了因为时钟微小偏差导致的误判。

关键实现点

  1. JWT生成
    • 在生成JWT的代码逻辑中,确保正确设置exp字段、nonce字段(如果采用该方案)以及iat字段。例如,在Java中使用JJWT库生成JWT时:
    String nonce = UUID.randomUUID().toString();
    Date now = new Date();
    Date expiration = new Date(now.getTime() + 15 * 60 * 1000); // 15分钟过期
    String token = Jwts.builder()
       .setSubject(user.getUsername())
       .claim("nonce", nonce)
       .setIssuedAt(now)
       .setExpiration(expiration)
       .signWith(SignatureAlgorithm.HS256, secretKey)
       .compact();
    
  2. JWT验证
    • 在各个微服务的JWT验证逻辑中,实现对expnonce(如果采用该方案)和iat字段的检查。以Java为例:
    Claims claims = Jwts.parserBuilder()
       .setSigningKey(secretKey)
       .build()
       .parseClaimsJws(token)
       .getBody();
    Date expiration = claims.getExpiration();
    if (expiration.before(new Date())) {
       throw new IllegalArgumentException("JWT已过期");
    }
    String nonce = claims.get("nonce", String.class);
    if (redisTemplate.hasKey(nonce)) {
       throw new IllegalArgumentException("重放攻击检测:该JWT已使用");
    }
    redisTemplate.opsForValue().set(nonce, "used", 15, TimeUnit.MINUTES); // 设置nonce使用记录并设置过期时间
    Date issuedAt = claims.getIssuedAt();
    long currentTime = System.currentTimeMillis();
    if (currentTime - issuedAt.getTime() > 5 * 60 * 1000) {
       throw new IllegalArgumentException("JWT签发时间超出允许范围");
    }
    
  3. 缓存管理
    • 如果采用nonce方案,要确保缓存(如Redis)的高可用性和性能。可以使用Redis集群来提高可用性,并且合理设置缓存的过期时间,避免缓存占用过多资源。例如,将nonce在缓存中的过期时间设置为比JWT的exp时间稍长,以保证在JWT有效期内能够检测到重放攻击。