Reputation: 671
I am particularly new to App development and have learnt lately about the entire Signing process of an apk, why it's mandatory and it's importance to prevent unauthorized and tampering of the app. One of the famous checks for Signature refers to using the PackageManager class to do signature verification. Is there any other method which checks for the META-INF directory in the apk itself for tampering or other abusive activities to verify the App is not tampered and intact with its original signature?
Upvotes: 4
Views: 3864
Reputation: 31
Best practice is Server Side Tampering Detection which can not be patched.
Here is how:
Use Android SafetyNet. This is how Android Pay validates itself.
The basic flow is:
If this passes, you can be fairly confident that the user is running a genuine version of your app on an unmodified system. The app should get an attestation when it starts up and send it along to your sever with every transaction request.
Note, however, this means:
Users who have rooted their phone will not pass these checks Users who have installed custom or third-party ROM/firmware/OS (eg Cyanogen) will not pass these checks
Users who do not have access to Google Play Services (eg Amazon devices, people in China) will not pass these checks
...and therefore will be unable to use your app. Your company needs to make a business decision as to whether or not these restrictions (and the accompanying upset users) are acceptable.
Finally, realize that this is not an entirely airtight solution. With root access and perhaps Xposed, it is possible to modify the SafetyNet library to lie to Google's servers, telling them the "right" answers to get a verification pass result that Google signs. In reality, SafetyNet just moves the goalposts and makes it harder for malicious actors. Since these checks ultimately have to run on a device out of your control, it is indeed impossible to design an entirely secure system.
Read an excellent analysis of how the internals of SafetyNet work here.
Upvotes: 1
Reputation: 31
private void crcTest() throws IOException {
boolean modified = false;
// required dex crc value stored as a text string.
// it could be any invisible layout element
long dexCrc = Long.parseLong(Main.MyContext.getString(R.string.dex_crc));
ZipFile zf = new ZipFile(Main.MyContext.getPackageCodePath());
ZipEntry ze = zf.getEntry("classes.dex");
if ( ze.getCrc() != dexCrc ) {
// dex has been modified
modified = true;
}
else {
// dex not tampered with
modified = false;
}
}
Upvotes: 0