我无法在我的应用程序中使用 Sendgrid 公钥验证。我已经配置了所有先决条件。 (添加了 API 密钥,启用了签名的 webhook 等)
这是我测试 webhook 的方法。
这是我验证签名的代码。这是 Sendgrid 提供的内容的精确副本here.
public boolean VerifySignature(ECPublicKey publicKey, byte[] payload, String signature, String timestamp)
throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException, IOException {
// prepend the payload with the timestamp
final ByteArrayOutputStream payloadWithTimestamp = new ByteArrayOutputStream();
payloadWithTimestamp.write(timestamp.getBytes());
payloadWithTimestamp.write(payload);
// create the signature object
final Signature signatureObject = Signature.getInstance("SHA256withECDSA", "BC");
signatureObject.initVerify(publicKey);
signatureObject.update(payloadWithTimestamp.toByteArray());
// decode the signature
final byte[] signatureInBytes = Base64.getDecoder().decode(signature);
// verify the signature
return signatureObject.verify(signatureInBytes);
}
现在,当从下面的控制器方法调用时,此方法始终返回 false。
@PostMapping("/sendgrid-callback")
public boolean acceptSendgridCallback(
@RequestBody String rawData,
@RequestHeader("X-Twilio-Email-Event-Webhook-Timestamp") String timestamp,
@RequestHeader("X-Twilio-Email-Event-Webhook-Signature") String signature
) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException, SignatureException, IOException, InvalidKeyException {
System.out.println("Req body = \n" + rawData);
ECPublicKey ecdsaKey = eventWebhook.ConvertPublicKeyToECDSA
("public key taken from sendgrid");
boolean b = eventWebhook.VerifySignature(ecdsaKey, rawData, signature, timestamp);
return b;
}
老实说,我找不到原因。
有人可以帮忙吗。
如果您使用单元测试或您自己的http请求进行测试,则需要在请求正文中添加
\r\n
才能通过验证。如果您使用实际的 sendgrid webhook 请求进行测试,则无需添加它。
sendgrid 有一个用于 Java 的辅助工具。
我稍微修改了一下
public class SendgridUtils {
// Assuming publicKeyStr is the base64-encoded public key
public static java.security.interfaces.ECPublicKey ConvertPublicKeyToECDSA(String publicKey)
throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException {
byte[] publicKeyInBytes = Base64.getDecoder().decode(publicKey);
Security.addProvider(new BouncyCastleProvider());
KeyFactory factory = KeyFactory.getInstance("ECDSA", "BC");
return (ECPublicKey) factory.generatePublic(new X509EncodedKeySpec(publicKeyInBytes));
}
/**
* Verify signed event webhook requests.
*
* @param publicKey: elliptic curve public key
* @param payload: event payload string in the request body
* @param signature: value obtained from the
* 'X-Twilio-Email-Event-Webhook-Signature' header
* @param timestamp: value obtained from the
* 'X-Twilio-Email-Event-Webhook-Timestamp' header
* @return true or false if signature is valid
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
* @throws InvalidKeyException
* @throws SignatureException
* @throws IOException
*/
public static boolean VerifySignature(ECPublicKey publicKey, String payload, String signature, String timestamp)
throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException, IOException {
return VerifySignature(publicKey, payload.getBytes(), signature, timestamp);
}
/**
* Verify signed event webhook requests.
*
* @param publicKey: elliptic curve public key
* @param payload: event payload bytes in the request body
* @param signature: value obtained from the
* 'X-Twilio-Email-Event-Webhook-Signature' header
* @param timestamp: value obtained from the
* 'X-Twilio-Email-Event-Webhook-Timestamp' header
* @return true or false if signature is valid
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
* @throws InvalidKeyException
* @throws SignatureException
* @throws IOException
*/
public static boolean VerifySignature(ECPublicKey publicKey, byte[] payload, String signature, String timestamp)
throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException, IOException, IOException {
// prepend the payload with the timestamp
final ByteArrayOutputStream payloadWithTimestamp = new ByteArrayOutputStream();
payloadWithTimestamp.write(timestamp.getBytes());
payloadWithTimestamp.write(payload);
// create the signature object
final Signature signatureObject = Signature.getInstance("SHA256withECDSA", "BC");
signatureObject.initVerify(publicKey);
signatureObject.update(payloadWithTimestamp.toByteArray());
// decode the signature
final byte[] signatureInBytes = Base64.getDecoder().decode(signature);
// verify the signature
return signatureObject.verify(signatureInBytes);
}
}
publicKey 你可以从 https://app.sendgrid.com/settings/mail_settings > Signed Event Webhook Requests 在验证密钥