验证 JsonWebToken 签名
Verify JsonWebToken signature
我收到了 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 );
}
要验证签名,您需要使用Base64Url编码的header和payload,用您的secret计算HMACSha256哈希,Base64Url编码结果并比较到原始签名。您当然需要 HMACSha256 算法和 Base64#Url 编码的库,但不需要特定的 JWT 库。
写成伪代码说明原理:
hash = HmacSHA256(header + "." + payload , secret)
这里header
是Base64Url编码的header,payload
是Base64Url编码的payload
result = Base64UrlEncode(hash)
result
现在可以与原始签名进行比较。
在另一个 answer 中,我描述了使用 nodes.js 和在线工具的过程。
一个 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...
}
我收到了 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 );
}
要验证签名,您需要使用Base64Url编码的header和payload,用您的secret计算HMACSha256哈希,Base64Url编码结果并比较到原始签名。您当然需要 HMACSha256 算法和 Base64#Url 编码的库,但不需要特定的 JWT 库。
写成伪代码说明原理:
hash = HmacSHA256(header + "." + payload , secret)
这里header
是Base64Url编码的header,payload
是Base64Url编码的payload
result = Base64UrlEncode(hash)
result
现在可以与原始签名进行比较。
在另一个 answer 中,我描述了使用 nodes.js 和在线工具的过程。
一个 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...
}