我正在接收JWT,并想验证其签名。 它未加密,基于base64编码,并使用HmacSha256签名。 它是用我知道的秘密签名的。
如果不使用https://jwt.io/上列出的第三方库(例如java-jwt,jpose4j等),我似乎找不到如何验证签名的任何示例。
可以这样做吗?
到目前为止我所拥有的:
private boolean validateSignature( String header, String data, String signature, String secretKey ) throws Exception {
Base64 base64 = new Base64( true );
SecretKeySpec secret = new SecretKeySpec( secretKey.getBytes(), "HmacSHA256" );
Mac mac = Mac.getInstance( "HmacSHA256" );
mac.init( secret );
byte[] hmacDataBytes = mac.doFinal( data.getBytes( StandardCharsets.UTF_8.name()) );
String hmacData = new String( hmacDataBytes );
return hmacData.equals( signature ); // Compare signatures here...
}
基于@pedrofb和@jps答案,这是解决方案:
private boolean validToken( String authToken, String key ) throws Exception {
String[] token = authToken.split( "\\." );
String header = token[0];
String payload = token[1];
String originalSignature = token[2];
SecretKeySpec secret = new SecretKeySpec( Base64.getDecoder().decode( key ), ALGORITM_HMACSHA256 );
Mac mac = Mac.getInstance( ALGORITM_HMACSHA256 );
mac.init( secret );
StringBuilder headerAndPayload = new StringBuilder( header ).append( "." ).append( payload );
byte[] signatureBytes = mac.doFinal( headerAndPayload.toString().getBytes( StandardCharsets.UTF_8.name() ) );
String calculatedSignature = Base64.getUrlEncoder().withoutPadding().encodeToString( signatureBytes );
return calculatedSignature.equals( originalSignature );
}
答案 0 :(得分:3)
JWT由base64url编码的三部分用点分隔
header.payload.signature
签名是根据header.payload
假设您的方法接收到base64url中的元素,则需要在header + "." + data
上计算HMAC,将结果编码为base64url,然后与签名字段进行比较
类似这样的东西:
private boolean validateSignature( String header, String data, String signature, String secretKey ) throws Exception {
SecretKeySpec secret = new SecretKeySpec( secretKey.getBytes(), "HmacSHA256" );
Mac mac = Mac.getInstance( "HmacSHA256" );
mac.init( secret );
String body = header + "." + data;
byte[] hmacDataBytes = mac.doFinal( body.getBytes( StandardCharsets.UTF_8.name()) );
String hmacData = Base64.getUrlEncoder().encodeToString( hmacDataBytes );
return hmacData.equals( signature ); // Compare signatures here...
}
答案 1 :(得分:2)
要验证签名,您需要获取Base64Url编码的标头和有效负载,使用秘密计算HMACSha256哈希,Base64Url对结果进行编码并将其与原始签名进行比较。当然,您需要HMACSha256算法和Base64#Url编码的库,但不需要特定的JWT库。
用伪代码编写以显示原理:
hash = HmacSHA256(header + "." + payload , secret)
这里header
是Base64Url编码的标头,payload
是Base64Url编码的有效载荷
result = Base64UrlEncode(hash)
result
现在可以与原始签名进行比较。
在另一本answer中,我使用node.js和在线工具描述了该过程。