面试题答案
一键面试针对中间人攻击
- 使用HTTPS:
- 原理:HTTPS通过SSL/TLS协议对传输的数据进行加密,使得中间人无法获取和篡改传输中的JWT。在服务器端配置SSL证书,所有与客户端的通信都通过HTTPS进行。例如,在Java的Spring Boot项目中,可以通过配置
server.ssl
相关属性来启用HTTPS。 - 示例:在Spring Boot的
application.properties
文件中添加以下配置:
- 原理:HTTPS通过SSL/TLS协议对传输的数据进行加密,使得中间人无法获取和篡改传输中的JWT。在服务器端配置SSL证书,所有与客户端的通信都通过HTTPS进行。例如,在Java的Spring Boot项目中,可以通过配置
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
- 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;
}
}
}
针对重放攻击
- 使用一次性令牌(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;
}
}
}
- 设置合理的过期时间:
- 原理:为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();