我正在尝试实施Sendgrid签名验证。我已经在Sendgrid webhook中配置了调用功能。 我从 sendgrid webhook 获取签名和时间戳,但验证始终失败, 议程是每当使用 Sendgrid API 密钥从项目触发邮件时,都会触发 Webhook 事件并获取签名和时间戳 来自 webhook 并处理签名验证。验证完成后,将有效负载保存到数据库中。
这是我的代码
控制器:
@PostMapping("/events")
public void webhookEvents(@RequestBody Set\<EmailEvents\> emailEvents, @RequestHeader("X-Twilio- Email-Event-Webhook-Timestamp") String timestamp,
@RequestHeader("X-Twilio-Email-Event-Webhook-Signature") String signature) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException, IOException, SignatureException, InvalidKeyException {
log.info("Inside webhookEvents...");
log.info("Signature ----->"+signature);
log.info("Timestamp ----->"+timestamp);
boolean verify = emailDataService.verifySendgridSignature(emailEvents,signature,timestamp);
log.info("Signature Verification : "+verify);
emailDataService.webhookEvents(emailEvents);
}
电子邮件活动:
public class EmailEvents {
public String email;
public int timestamp;
@SerializedName("smtp-id")
public String smtp_id;
public String event;
public ArrayList<String> category;
public String sg_event_id;
public String sg_message_id;
private String useragent;
private String ip;
private boolean sg_machine_open;
private String emailUUID;
private String sentDate;
}
电子邮件数据服务:
private EventWebhook ew = new EventWebhook();
final String publicKey = "XXXXXX";
public boolean verifySendgridSignature(Set<EmailEvents> emailEvents,String signature,String timestamp) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException, IOException, SignatureException, InvalidKeyException {
String payload = new ObjectMapper().writeValueAsString(emailEvents);
final ECPublicKey ellipticCurvePublicKey = ew.ConvertPublicKeyToECDSA(publicKey);
final boolean valid = ew.VerifySignature(ellipticCurvePublicKey,payload , signature, timestamp);
System.out.println("Valid Signature: " + valid);
return valid;
}
EventWebhook:
public class EventWebhook {
public java.security.interfaces.ECPublicKey ConvertPublicKeyToECDSA(String publicKey)
throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException {
Security.addProvider(new BouncyCastleProvider());
byte[] publicKeyInBytes = Base64.getDecoder().decode(publicKey);
KeyFactory factory = KeyFactory.getInstance("ECDSA", "BC");
return (ECPublicKey) factory.generatePublic(new X509EncodedKeySpec(publicKeyInBytes));
}
public boolean VerifySignature(ECPublicKey publicKey, String payload, String signature, String timestamp)
throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException, IOException {
return VerifySignature(publicKey, payload.getBytes(), signature, timestamp);
}
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);
}
}
这将有助于解决这个问题。验证有效负载时,您需要添加将 {,} 替换为新行。当我阅读有关服务器较少实现的文档时,我发现了这一点。 https://www.twilio.com/docs/serverless/functions-assets/quickstart/validate-webhook-requests-from-sendgrid
public void handleSendGridEvents(HttpServletRequest request) {
StringBuilder stringBuilder = new StringBuilder();
request.getReader().lines().forEach(stringBuilder::append);
String rawPayload = stringBuilder.toString();
String adjustedPayload = rawPayload
.replace("},{", "},\r\n{")
.concat("\r\n");
String signature = request.getHeader(EventWebhookHeader.SIGNATURE.name);
String timestamp = request.getHeader(EventWebhookHeader.TIMESTAMP.name);
EventWebhook eventWebhook = new EventWebhook();
ECPublicKey publicKey = eventWebhook.ConvertPublicKeyToECDSA(VERIFICATION_KEY);
boolean isValid = eventWebhook.VerifySignature(publicKey, adjustedPayload, signature, timestamp); }