在對接微信支付接口時,需要對微信支付返回的信息進行簽名驗證,防止中間人攻擊,替換微信支付返回的結果
整體過程
- 微信支付生成簽名:私鑰 + 內容
->
signature - 調用方驗證簽名:公鑰 + 內容
驗證
signature
示例
- 生成簽名
/**
* 生成簽名.
*
* @param originalData 原始數據
* @param privateKey 私鑰
* @return 簽名串
*/
public static String sign(String originalData, PrivateKey privateKey) {
String base64Sign = "";
try {
//返回指定簽名的Signature對象
Signature sign = Signature.getInstance("SHA1withRSA");
//初始化這個用於簽名的對象
sign.initSign(privateKey);
byte[] bysData = originalData.getBytes(StandardCharsets.UTF_8);
//使用指定的byte數組更新要簽名的數據
sign.update(bysData);
//返回所有已經更新數據的簽名字節
byte[] signByte = sign.sign();
//對其進行Base64編碼
BASE64Encoder encoder = new BASE64Encoder();
base64Sign = encoder.encode(signByte);
} catch (Exception e) {
throw new RuntimeException(e);
}
return base64Sign;
}
- 驗證簽名
/**
* 驗證簽名.
*
* @param signStr 簽名串
* @param originalData 原始數據
* @param publicKey 公鑰
* @return 是否驗證通過
*/
public static boolean verify(String signStr, String originalData, PublicKey publicKey) {
System.out.println("開始進行驗籤,原始數據爲:" + originalData);
try {
//將簽名數據
BASE64Decoder decoder = new BASE64Decoder();
byte[] signed = decoder.decodeBuffer(signStr);
//通過Signature的getInstance方法,獲取指定簽名算法的Signature對象
Signature signature = Signature.getInstance("SHA1withRSA");
//初始化用於驗證的對象
signature.initVerify(publicKey);
//使用指定的byte[]更新要驗證的數據
signature.update(originalData.getBytes(StandardCharsets.UTF_8));
//驗證傳入的簽名
return signature.verify(signed);
} catch (Exception e) {
return false;
}
}
- 測試
public static void main(String[] args) throws Exception {
String p12 = "KLFJDLJFL";
byte[] decode = Base64.getDecoder().decode(p12);
String keypasswd = "passwd";
String keyalias = "tenpay certificate";
KeyStore ks = KeyStore.getInstance("PKCS12");
ks.load(new ByteArrayInputStream(decode), keypasswd.toCharArray());
Enumeration<String> aliases = ks.aliases();
while (aliases.hasMoreElements()) {
System.out.println(aliases.nextElement());
}
PrivateKey prikey = (PrivateKey) ks.getKey(keyalias, keypasswd.toCharArray());
Certificate cert = ks.getCertificate(keyalias);
PublicKey pubkey = cert.getPublicKey();
String originData = "hello world";
String sign = sign(originData, prikey);
boolean verify = verify(sign, originData, pubkey);
System.out.println(verify);
}
疑問
使用了HTTPS,爲什麼微信支付還要用公私鑰簽名呢?