MST
星途 面试题库

面试题:安全认证:JWT跨域时应对常见攻击的策略

在基于JWT的跨域资源共享解决方案中,可能会面临如中间人攻击、重放攻击等安全威胁。请详细说明针对这些常见攻击,你会采取哪些具体的策略和措施来保障认证的安全性。
39.0万 热度难度
后端开发安全认证

知识考点

AI 面试

面试题答案

一键面试

针对中间人攻击

  1. 使用HTTPS
    • 原理:HTTPS通过SSL/TLS协议对传输的数据进行加密,使得中间人无法获取和篡改传输中的JWT。在服务器端配置SSL证书,所有与客户端的通信都通过HTTPS进行。例如,在Java的Spring Boot项目中,可以通过配置server.ssl相关属性来启用HTTPS。
    • 示例:在Spring Boot的application.properties文件中添加以下配置:
server.ssl.key-store=classpath:keystore.jks
server.ssl.key-store-password=password
server.ssl.key-password=password
server.ssl.key-alias=tomcat
server.port=8443
  1. JWT签名验证
    • 原理:JWT包含一个签名部分,服务器在验证JWT时,会使用与生成JWT时相同的密钥(对称加密)或私钥(非对称加密)来验证签名。如果中间人篡改了JWT的内容,签名验证将失败。
    • 示例:在Java中使用jjwt库验证JWT签名。假设已经获取到JWT字符串jwt和密钥secret
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import javax.crypto.SecretKey;

public class JwtValidator {
    public static boolean validateJwt(String jwt, String secret) {
        try {
            SecretKey key = Keys.hmacShaKeyFor(secret.getBytes());
            Claims claims = Jwts.parserBuilder()
                  .setSigningKey(key)
                  .build()
                  .parseClaimsJws(jwt)
                  .getBody();
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

针对重放攻击

  1. 使用一次性令牌(Nonce)
    • 原理:在生成JWT时,添加一个唯一的一次性令牌(Nonce)作为JWT的一个声明(claim)。服务器维护一个已使用Nonce的列表,每次验证JWT时,检查Nonce是否已经使用过。如果是,则拒绝该JWT。
    • 示例:在生成JWT时添加Nonce:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import javax.crypto.SecretKey;
import java.util.Date;
import java.util.UUID;

public class JwtGenerator {
    public static String generateJwt(String subject, String secret) {
        SecretKey key = Keys.hmacShaKeyFor(secret.getBytes());
        String nonce = UUID.randomUUID().toString();
        Claims claims = Jwts.claims().setSubject(subject);
        claims.put("nonce", nonce);
        Date now = new Date();
        Date expiration = new Date(now.getTime() + 3600000); // 1小时过期
        return Jwts.builder()
              .setClaims(claims)
              .setIssuedAt(now)
              .setExpiration(expiration)
              .signWith(key, SignatureAlgorithm.HS256)
              .compact();
    }
}

在验证JWT时检查Nonce:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import javax.crypto.SecretKey;
import java.util.HashSet;
import java.util.Set;

public class JwtValidator {
    private static Set<String> usedNonces = new HashSet<>();
    public static boolean validateJwt(String jwt, String secret) {
        try {
            SecretKey key = Keys.hmacShaKeyFor(secret.getBytes());
            Claims claims = Jwts.parserBuilder()
                  .setSigningKey(key)
                  .build()
                  .parseClaimsJws(jwt)
                  .getBody();
            String nonce = (String) claims.get("nonce");
            if (usedNonces.contains(nonce)) {
                return false;
            }
            usedNonces.add(nonce);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}
  1. 设置合理的过期时间
    • 原理:为JWT设置较短的过期时间,这样即使JWT被重放,在过期后也会失效。例如,对于一些敏感操作的JWT,可以设置几分钟的过期时间;对于一般的用户认证JWT,可以设置1小时左右的过期时间。
    • 示例:在生成JWT时设置过期时间,如上述JwtGenerator类中设置expiration为1小时后过期。
Date now = new Date();
Date expiration = new Date(now.getTime() + 3600000); // 1小时过期
return Jwts.builder()
     .setClaims(claims)
     .setIssuedAt(now)
     .setExpiration(expiration)
     .signWith(key, SignatureAlgorithm.HS256)
     .compact();