使用RSA公钥验证Webhook签名时Java方法始终返回false的问题求助
RSA公钥验证Webhook签名时Java方法始终返回false的问题求助
大家好,我最近在处理Webhook签名验证的问题,遇到了一个棘手的情况:我的Java验证方法始终返回false,但我确认传入的请求头和请求体都是正确的,按服务商的规则应该验证通过才对。想请各位帮忙排查下问题所在。
问题详情
我的Java签名验证方法无论怎么测试都返回false,但实际传入的请求头和请求体都是正确的,理论上应该返回TRUE。
服务商文档说明
Signature = Base64(RSA512(WEBHOOK_PRIVATE_KEY, SHA512(eventBody)))
相关信息
公钥
-----BEGIN PUBLIC KEY----- MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0+6wd9OJQpK60ZI7qnZG jjQ0wNFUHfRv85Tdyek8+ahlg1Ph8uhwl4N6DZw5LwLXhNjzAbQ8LGPxt36RUZl5 YlxTru0jZNKx5lslR+H4i936A4pKBjgiMmSkVwXD9HcfKHTp70GQ812+J0Fvti/v 4nrrUpc011Wo4F6omt1QcYsi4GTI5OsEbeKQ24BtUd6Z1Nm/EP7PfPxeb4CP8KOH clM8K7OwBUfWrip8Ptljjz9BNOZUF94iyjJ/BIzGJjyCntho64ehpUYP8UJykLVd CGcu7sVYWnknf1ZGLuqqZQt4qt7cUUhFGielssZP9N9x7wzaAIFcT3yQ+ELDu1SZ dE4lZsf2uMyfj58V8GDOLLE233+LRsRbJ083x+e2mW5BdAGtGgQBusFfnmv5Bxqd HgS55hsna5725/44tvxll261TgQvjGrTxwe7e5Ia3d2Syc+e89mXQaI/+cZnylNP SwCCvx8mOM847T0XkVRX3ZrwXtHIA25uKsPJzUtksDnAowB91j7RJkjXxJcz3Vh1 4k182UFOTPRW9jzdWNSyWQGl/vpe9oQ4c2Ly15+/toBo4YXJeDdDnZ5c/O+KKadc IMPBpnPrH/0O97uMPuED+nI6ISGOTMLZo35xJ96gPBwyG5s2QxIkKPXIrhgcgUnk tSM7QYNhlftT4/yVvYnk0YcCAwEAAQ== -----END PUBLIC KEY-----
签名请求头
YNYVgWsx3PdoEGq2nUFGLmE6tE2y0LCc/eWPSY+rAqK+8fcxrPN0SPGbTdAXQ9+v62T5akWaVRWKXc1YBWlZxhVTCa/Ou7FfjVPG6JIQNX3Lks3ZhW0k29bVKf7Qvjp7z8HM9s1D8ZC28HvpX15a4by7DpNKkQ6cLWMDtBvqY02FSO+L4Vq54GZoTrplYkqCYcI4/oWchYzMZMq4omIOuam2DXm5BLlZ7HCR/nhUyp5duJpYnWJCKEwOTh3zLm842r5Fa9humq9WKkkT+AgFxe95bG4F3p8XhsciXiaNgx8diKLF0aBklqJ6yA70vjIP92BHuEnvIl37RiSFiIvkYWvLpMc1LoPxWZvncaLUjlYSVT3zd/gCDPEn1Mu8wUogGt9npkc/eKMdrKefcjEIMrJoO0HMMREZcOpc72F0+RM4QCkMaQMmK4zq9cBF0E2bNaEabNDSWXIfx9fa2VuyGYa5GLmAPUQPYRv50n92IGFewxj9vFAWhca+uthvsqz3FekyHK+c9G1Wh9OScR2TQp9Lbe4LqlX4FGapQitmfDvKRJhjAVm0n5355+k1dRse4fGeXqd2EfledWUJ3egpmW1NlmWBr8d4PsruKYZnphEMn9F5F3Vyu2sCpBSvqmcMANXzyZP7u3lGsUpH4V2lM6nCeBiRcbfwyrFsJ6Q5dso=
请求体
{"type":"TRANSACTION_STATUS_UPDATED","tenantId":"f4df1e73-ec68-53c5-aa92-1a2bc45900ef","timestamp":1671288284087,"data":{"id":"b96f37dd-0fe9-4aa0-853b-f7d39c2ddc52","createdAt":1671286112004,"lastUpdated":1671286112019,"assetId":"BTC_TEST","source":{"id":"","type":"UNKNOWN","name":"External","subType":""},"destination":{"id":"26","type":"VAULT_ACCOUNT","name":"55b49ae0-0f34-4b3c-8cf6-0094254261c2","subType":""},"amount":1.0E-5,"networkFee":1.41E-6,"netAmount":1.0E-5,"sourceAddress":"tb1qluc5wgms8kpu0tydu00590qryfan3969jvmc8e","destinationAddress":"tb1qyhfnsfe2dy8az3040yvx087qdfsw6yxk8pc7yj","destinationAddressDescription":"","destinationTag":"","status":"CONFIRMING","txHash":"15873dc631db22a1bd13c6adecf7fb63f8fbbecce36eb38d12df65573e83dfa9","subStatus":"PENDING_BLOCKCHAIN_CONFIRMATIONS","signedBy":[],"createdBy":"","rejectedBy":"","amountUSD":0.17,"addressType":"","note":"","exchangeTxId":"","requestedAmount":1.0E-5,"feeCurrency":"BTC_TEST","operation":"TRANSFER","customerRefId":null,"numOfConfirmations":2,"amountInfo":{"amount":"0.00001","requestedAmount":"0.00001","netAmount":"0.00001","amountUSD":"0.17"},"feeInfo":{"networkFee":"0.00000141"},"destinations":[],"externalTxId":null,"blockInfo":{"blockHeight":"2411637","blockHash":"00000000d45b7ebf40921cbc70fb6791985a0b256241757a28bf762be07478e8"},"signedMessages":[],"index":1}}
我的Java验证代码
签名验证核心方法
public boolean matches(WebhookEvent body, String header){ try { File publicKeyFile = new File("publicKey.pub"); byte[] bytes = PemUtils.parsePEMFile(publicKeyFile); KeyFactory kf = KeyFactory.getInstance("RSA"); X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes); PublicKey publicKey = kf.generatePublic(spec); ObjectMapper objectMapper = new ObjectMapper(); String message = objectMapper.writeValueAsString(body); Signature verifier = Signature.getInstance("SHA512withRSA"); verifier.initVerify(publicKey); verifier.update(message.getBytes()); boolean isVerified = verifier.verify(Base64.getDecoder().decode(header)); System.out.println("Verified: " + isVerified); return isVerified; } catch (Exception e){ log.error("Error while verifying signature : " + e.getMessage()); e.printStackTrace(); return false; } }
PEM文件解析工具类
static byte[] parsePEMFile(File pemFile) throws IOException { if (!pemFile.isFile() || !pemFile.exists()) { throw new FileNotFoundException(String.format("The file '%s' doesn't exist.", pemFile.getAbsolutePath())); } PemReader reader = new PemReader(new FileReader(pemFile)); PemObject pemObject = reader.readPemObject(); byte[] content = pemObject.getContent(); reader.close(); return content; }
相关POJO类
WebhookEvent
@Data @JsonIgnoreProperties(ignoreUnknown = true) public class WebhookEvent { @JsonProperty(value = "type") private FireblocksEventType eventType; @JsonProperty(value = "tenantId") private String tenantId; @JsonProperty(value = "timestamp") private long timestamp; @JsonProperty(value = "data") private TransactionDetailObject eventData; }
TransactionDetailObject
@Data @JsonIgnoreProperties(ignoreUnknown = true) public class TransactionDetailObject { private String id; private String assetId; private TransferPeerPathResponse source; private TransferPeerPathResponse destination; private BigDecimal requestedAmount; private AmountInfo amountInfo; private FeeInfo feeinfo; private BigDecimal amount; private BigDecimal netAmount; private BigDecimal amountUSD; private BigDecimal serviceFee; private Boolean treatAsGrossAmount; private BigDecimal networkFee; private Long createdAt; private Long lastUpdated; private TransactionStatus status; private String txHash; private Long index; private TransactionSubStatus subStatus; private String sourceAddress; private String destinationAddress; private String destinationAddressDescription; private String destinationTag; private List<String> signedBy; private String createdBy; private String rejectedBy; private String addressType; private String note; private String exchangeTxId; private String feeCurrency; private TransactionOperation operation; private AmlScreeningResult amlScreeningResult; private String customerRefId; private Long numOfConfirmations; private List<NetworkRecord>networkRecords; private String replacedTxHash; private String externalTxId; private List<DestinationResponse>destinations; private BlockInfo blockInfo; private RewardsInfo rewardsInfo; private AuthorizationInfo authorizationInfo; private List<SignedMessage>signedMessages; private Object extraParameters; }
备注:内容来源于stack exchange,提问作者Gladiator9120
相关产品推荐
相关产品推荐

