【发布时间】:2015-06-20 20:59:52
【问题描述】:
我有一个使用 Paypal Restful Webhooks 的 Java servlet。在验证请求签名时,我按照
中详述的说明进行操作但是,即使按照 paypal 文档中的伪代码进行操作,我似乎也无法成功验证签名。这是我用来验证的实际代码(下面的方法总是返回 false):
private static final String WEBHOOK_ID = "4HL82785RC0XXXXXX";
private boolean isValidRequest(HttpServletRequest req, String payload) throws Exception {
String transmissionId = req.getHeader("PAYPAL-TRANSMISSION-ID");
String timeStamp = req.getHeader("PAYPAL-TRANSMISSION-TIME");
String crc32 = getCrcSum(payload);
String expectedSignature = String.format("%s|%s|%s|%s", transmissionId, timeStamp, WEBHOOK_ID, crc32);
System.out.println("EXPECTED SIG:" + expectedSignature);
String actualSignatureEncoded = req.getHeader("PAYPAL-TRANSMISSION-SIG");
String certUrl = req.getHeader("PAYPAL-CERT-URL");
String algo = req.getHeader("PAYPAL-AUTH-ALGO");
Signature shaWithRsa = Signature.getInstance(algo);
byte[] certData = HttpUtils.getBytes(new URL(certUrl), null);
Certificate certificate = X509Certificate.getInstance(certData);
shaWithRsa.initVerify(certificate.getPublicKey());
shaWithRsa.update(expectedSignature.getBytes());
byte[] actualSignature = Base64.decodeBase64(actualSignatureEncoded.getBytes());
return shaWithRsa.verify(actualSignature);
}
private static String getCrcSum(final String body) {
byte[] bytes = body.getBytes();
CRC32 checkSum = new CRC32();
checkSum.update(bytes, 0, bytes.length);
return String.valueOf(checkSum.getValue());
//return Long.toHexString(checkSum.getValue());
}
HttpUtils.getBytes(new URL(certUrl), null);只是用于检索 GET 请求结果的辅助方法。它返回一个有效的证书。
我能想到的可能罪魁祸首是: 1. CRC32 的计算与 Paypal 的计算方式有所不同。 2. Paypal URL 中的公钥与 Paypal 使用的私钥不匹配。
这是我从 servlet 请求中获取有效负载的方法:
String payload = getString(req.getInputStream());
private static String getString(InputStream is) {
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
String line;
try {
br = new BufferedReader(new InputStreamReader(is));
while ((line = br.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
我使用https://developer.paypal.com/developer/webhooksSimulator 进行测试。
【问题讨论】:
-
检查您的 WEBHOOK_ID 并查看它是否是您在检查时间的预期值
-
您好丹尼尔,感谢您的回复!不幸的是,运行时的 WEBHOOK_ID 是正确的。我使用
System.out.println("EXPECTED SIG:" + expectedSignature);打印输出检查了它。
标签: java rest servlets encryption paypal