我试图在我的登录过程之前检测我的应用程序上的根设备。关于这个答案,我决定使用 SafetyNet。我像这样编辑了这段代码:
public class RootedDeviceCheckWithSafetyNetAttestation {
public static AtomicInteger sendSafetyNetRequest(Activity context) {
AtomicInteger rootCheck = new AtomicInteger();
if(GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS) {
Log.e(TAG, "The SafetyNet Attestation API is available");
// TODO(developer): Change the nonce generation to include your own, used once value,
// ideally from your remote server.
String nonceData = "Safety Net Sample: " + System.currentTimeMillis();
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
Random mRandom = new SecureRandom();
byte[] bytes = new byte[24];
mRandom.nextBytes(bytes);
try {
byteStream.write(bytes);
byteStream.write(nonceData.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
byte[] nonce = byteStream.toByteArray();
SafetyNetClient client = SafetyNet.getClient(context);
Task<SafetyNetApi.AttestationResponse> task = client.attest(nonce, MY-API-KEY);
task.addOnSuccessListener(context, attestationResponse -> {
/*
TODO(developer): Forward this result to your server together with
the nonce for verification.
You can also parse the JwsResult locally to confirm that the API
returned a response by checking for an 'error' field first and before
retrying the request with an exponential backoff.
NOTE: Do NOT rely on a local, client-side only check for security, you
must verify the response on a remote server!
*/
String jwsResult = attestationResponse.getJwsResult();
Log.e(TAG, "Success! SafetyNet result:\n" + jwsResult + "\n");
if (jwsResult == null) {
Log.e(TAG, "jwsResult Null");
}
final String[] jwtParts = jwsResult.split("\\.");
if (jwtParts.length == 3) {
String decodedPayload = new String(Base64.decode(jwtParts[1], Base64.DEFAULT));
try {
JSONObject jsonObject = new JSONObject(decodedPayload);
//Toast.makeText(context, "ctsProfileMatch:" + jsonObject.getString("ctsProfileMatch")+","+"basicIntegrity:" + jsonObject.getString("basicIntegrity"), Toast.LENGTH_SHORT).show();
if((jsonObject.getString("ctsProfileMatch").equals("false")) && (jsonObject.getString("basicIntegrity").equals("false"))){
rootCheck.set(4);
}
else{
rootCheck.set(1);
}
} catch (JSONException e) {
e.printStackTrace();
rootCheck.set(2);
}
//Toast.makeText(context, decodedPayload, Toast.LENGTH_SHORT).show();
//Log.e(TAG, "decodedPayload : " + decodedPayload);
}
});
task.addOnFailureListener(context, e -> {
// An error occurred while communicating with the service.
String mResult = null;
rootCheck.set(5);
if (e instanceof ApiException) {
// An error with the Google Play Services API contains some additional details.
ApiException apiException = (ApiException) e;
Log.e(TAG, "Error: " +
CommonStatusCodes.getStatusCodeString(apiException.getStatusCode()) + ": " +
apiException.getStatusMessage());
Toast.makeText(context, "Error: " +
CommonStatusCodes.getStatusCodeString(apiException.getStatusCode()) + ": " +
apiException.getStatusMessage(), Toast.LENGTH_LONG).show();
} else {
// A different, unknown type of error occurred.
Log.e(TAG, "ERROR! " + e.getMessage());
Toast.makeText(context, "ERROR! " + e.getMessage(), Toast.LENGTH_LONG).show();
}
});
} else {
Log.e(TAG, "Prompt user to update Google Play services.");
rootCheck.set(3);
}
return rootCheck;
}
}
当我尝试在模拟器或有根设备上时,我可以看到我的rootCheck
变量变成4
了我用代码编写的。
问题是; 在真实手机中,第一次登录时,我的代码也可以检测到有根设备。但是,如果我关闭应用程序并从后台终止并再次重新打开,我会看到我的代码给出了这个 toast Error: CANCELLED: null
,所以我看到了那个rootCheck
变量5
,这意味着跳转task.addOnFailureListener
到if (e instanceof ApiException)
. 这个问题在有根和正常设备上引起,没关系。
问题是什么?你能帮助我吗 ?