SendGrid签名验证始终失败,请求排查解决方案
问题:SendGrid Webhook签名验证始终失败
我正在实现SendGrid签名验证功能,已在SendGrid Webhook中配置回调函数,目前能正常获取Webhook返回的signature(签名)和timestamp(时间戳),但签名验证一直不通过。
需求说明:当项目通过SendGrid API密钥触发邮件发送时,触发Webhook事件,获取签名和时间戳完成验证,验证通过后将载荷存入数据库。
以下是我的代码:
Controller代码
@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); }
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; }
EmailDataService业务类
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); } }
排查方向
- 公钥格式问题:确认从SendGrid获取的公钥是否完整,若包含
-----BEGIN PUBLIC KEY-----和-----END PUBLIC KEY-----标识,需先去除再进行Base64解码。 - Payload序列化不一致:SendGrid签名基于原始请求体字节流生成,而代码中用
ObjectMapper将解析后的对象重新序列化,可能因字段顺序、空格、转义符差异导致哈希值不匹配。建议直接读取原始请求体的字节数组,而非通过@RequestBody解析后再序列化。 - 字符编码不统一:拼接timestamp和payload时,显式指定UTF-8编码(SendGrid默认编码),避免系统默认编码差异。例如将
timestamp.getBytes()改为timestamp.getBytes(StandardCharsets.UTF_8)。 - 签名算法匹配:尝试将签名算法改为
SHA256withECDSAinP1363Format,部分环境下该格式与SendGrid签名生成逻辑更匹配。 - 时间戳有效性:添加时间戳时效性验证,确保请求未被重放,同时确认timestamp与签名属于同一请求。
内容的提问来源于stack exchange,提问作者Dhanyesh
相关产品推荐
相关产品推荐

