背景:
我们有一个Android应用程序,目前通过Google Play销售。为了使应用程序正常运行,用户必须通过应用内支付购买一个“令牌”。这个“令牌”是一次性的,使用一次后就不能再用了。为了验证该令牌,我们将购买数据发送到服务器,并使用标准的Java RSA安全代码来验证从Play商店返回的信息是否有效(如下所示)。 我们在发布应用程序之前进行了广泛的测试,即使应用程序已经上架,我们也进行了更多的测试。从Google返回的数据每次都通过了验证。然后,在12月初左右,签名验证开始失败。我们没有改变代码或商店中的应用程序,服务器上的验证代码也保持不变。
我调试了代码,并运行从Play Store返回的收据数据和签名数据,确实无法通过验证。我不知道发生了什么变化,或者为什么会出现验证失败的情况。
问题:
有人遇到过这种情况吗?即应用程序未更改时签名验证失败?您有哪些提示可以提供,以便开始查找问题的原因?
更多信息:
我唯一想到的更改是,Google发布了应用内支付API v3,但这不应影响我们使用的V2。
为了辅助开发,我们使用net.robotmedia.billing库来处理应用内支付。
下面是从Play商店返回的数据的服务器验证代码:
其中,encodePublicKey => 是我们从Play Store获取的公钥
signedData => 是从Play Store购买时返回的base64编码的收据数据
signature => 是从Play Store返回的签名
public class Security {
public final static Logger logger = Logger.getLogger(Security.class.getName());
private static final String KEY_FACTORY_ALGORITHM = "RSA";
private static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
/**
* Generates a PublicKey instance from a string containing the
* Base64-encoded public key.
*
* @param encodedPublicKey
* Base64-encoded public key
* @throws IllegalArgumentException
* if encodedPublicKey is invalid
*/
public static PublicKey generatePublicKey(String encodedPublicKey) {
try {
byte[] decodedKey = Base64.decode(encodedPublicKey);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM);
return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
}
catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
catch (InvalidKeySpecException e) {
logger.error("Invalid key specification.", e);
throw new IllegalArgumentException(e);
}
catch (Base64DecoderException e) {
logger.error("Base64 decoding failed.", e);
throw new IllegalArgumentException(e);
}
}
/**
* Verifies that the signature from the server matches the computed
* signature on the data. Returns true if the data is correctly signed.
*
* @param publicKey
* public key associated with the developer account
* @param signedData
* signed data from server
* @param signature
* server signature
* @return true if the data and signature match
*/
public static boolean verify(PublicKey publicKey, String signedData, String signature) {
Signature sig;
try {
sig = Signature.getInstance(SIGNATURE_ALGORITHM);
sig.initVerify(publicKey);
sig.update(signedData.getBytes());
byte[] decodedSig = Base64.decode(signature);
if (!sig.verify(decodedSig)) {
logger.error("Signature verification failed.");
return false;
}
return true;
}
catch (NoSuchAlgorithmException e) {
logger.error("NoSuchAlgorithmException.");
}
catch (InvalidKeyException e) {
logger.error("Invalid key specification.");
}
catch (SignatureException e) {
logger.error("Signature exception.");
}
catch (Base64DecoderException e) {
logger.error("Base64 decoding failed.");
}
return false;
}
}
getBytes()
等),它应该能够工作。剩下的问题可能是PlayStore服务器上的一些错误,你可以尝试联系他们。 - Nikolay Elenkov