SendGrid - 签名验证一直失败

问题描述 投票:0回答:1

我正在尝试实施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);
  }
 }
twilio webhooks sendgrid ecdsa sendgrid-api-v3
1个回答
0
投票

这将有助于解决这个问题。验证有效负载时,您需要添加将 {,} 替换为新行。当我阅读有关服务器较少实现的文档时,我发现了这一点。 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); }
© www.soinside.com 2019 - 2024. All rights reserved.