使用云服务器解码和验证令牌更好。
例如,如果您使用 Java 服务,那么下面的代码会将完整性令牌发送到 google 服务器,因此您可以验证响应。
针对该应用在 Google Cloud Platform 中启用 PlayIntegrity API 并下载 JSON 文件并在代码中进行配置。
同样,您应该在 Google PlayConsole 中针对应用启用 PlayIntegrity API
将 Google Play Integrity Client Library 添加到您的项目中
Maven 依赖
<project>
<dependencies>
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-playintegrity</artifactId>
<version>v1-rev20220211-1.32.1</version>
</dependency>
</dependencies>
分级
repositories {
mavenCentral()
}
dependencies {
implementation 'com.google.apis:google-api-services-playintegrity:v1-rev20220211-1.32.1'
}
令牌解码
DecodeIntegrityTokenRequest requestObj = new DecodeIntegrityTokenRequest();
requestObj.setIntegrityToken(request.getJws());
//Configure downloaded Json file
GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream("<Path of JSON file>\\file.json"));
HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(credentials);
HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
JsonFactory JSON_FACTORY = new JacksonFactory();
GoogleClientRequestInitializer initialiser = new PlayIntegrityRequestInitializer();
Builder playIntegrity = new PlayIntegrity.Builder(HTTP_TRANSPORT, JSON_FACTORY, requestInitializer).setApplicationName("testapp")
.setGoogleClientRequestInitializer(initialiser);
PlayIntegrity play = playIntegrity.build();
DecodeIntegrityTokenResponse response = play.v1().decodeIntegrityToken("com.test.android.integritysample", requestObj).execute();
那么响应如下
{
"tokenPayloadExternal": {
"accountDetails": {
"appLicensingVerdict": "LICENSED"
},
"appIntegrity": {
"appRecognitionVerdict": "PLAY_RECOGNIZED",
"certificateSha256Digest": ["pnpa8e8eCArtvmaf49bJE1f5iG5-XLSU6w1U9ZvI96g"],
"packageName": "com.test.android.integritysample",
"versionCode": "4"
},
"deviceIntegrity": {
"deviceRecognitionVerdict": ["MEETS_DEVICE_INTEGRITY"]
},
"requestDetails": {
"nonce": "SafetyNetSample1654058651834",
"requestPackageName": "com.test.android.integritysample",
"timestampMillis": "1654058657132"
}
}
}
检查许可证
String licensingVerdict = response.getTokenPayloadExternal().getAccountDetails().getAppLicensingVerdict();
if(!licensingVerdict.equalsIgnoreCase("LICENSED")) {
throw new Exception("Licence is not valid.");
}
验证应用完整性
public void checkAppIntegrity(DecodeIntegrityTokenResponse response, String appId) throws Exception {
AppIntegrity appIntegrity = response.getTokenPayloadExternal().getAppIntegrity();
if(!appIntegrity.getAppRecognitionVerdict().equalsIgnoreCase("PLAY_RECOGNIZED")) {
throw new Exception("The certificate or package name does not match Google Play records.");
}
if(!appIntegrity.getPackageName().equalsIgnoreCase(appId)) {
throw new Exception("App package name mismatch.");
}
if(appIntegrity.getCertificateSha256Digest()!= null) {
//If the app is deployed in Google PlayStore then Download the App signing key certificate from Google Play Console (If you are using managed signing key).
//otherwise download Upload key certificate and then find checksum of the certificate.
Certificate cert = getCertificate("<Path to Signing certificate>\deployment_cert.der");
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] der = cert.getEncoded();
md.update(der);
byte[] sha256 = md.digest();
//String checksum = Base64.getEncoder().encodeToString(sha256);
String checksum = Base64.getUrlEncoder().encodeToString(sha256);
/** Sometimes checksum value ends with '=' character, you can avoid this character before perform the match **/
checksum = checksum.replaceAll("=","");
if(!appIntegrity.getCertificateSha256Digest().get(0).contains(checksum)) {
throw new Exception("App certificate mismatch.");
}
}
}
public static Certificate getCertificate(String certificatePath)
throws Exception {
CertificateFactory certificateFactory = CertificateFactory
.getInstance("X509");
FileInputStream in = new FileInputStream(certificatePath);
Certificate certificate = certificateFactory
.generateCertificate(in);
in.close();
return certificate;
}
验证设备完整性
//Check Device Integrity
public void deviceIntegrity(DecodeIntegrityTokenResponse response) {
DeviceIntegrity deviceIntegrity = response.getTokenPayloadExternal().getDeviceIntegrity();
if(!deviceIntegrity.getDeviceRecognitionVerdict().contains("MEETS_DEVICE_INTEGRITY")) {
throw new Exception("Does not meet Device Integrity.");
}
}
类似地,您可以使用以前存储在服务器中的数据来验证 Nonce 和应用程序包名称