12

I have a payment application in my device, my application connect to that application's service to get a pending-intent for launch payment activity and then listen to result in onActivityResult() method.(similar to In-App-Purchase scenario)

I set package name for payment intent. but you know, it's not guarantee payment application is trusted. if some one install fake application through unknown source with same package name and same aidl-service implementation then it can give me pending-intent and phishing my user info.

I verify payment result with some mechanism and that only safe my application from fake payment result but my application user enter their data in phisher application. (this paragraph say my problem is not trusting response of payment application, my problem is trusting payment application before launch their activity)

I know some approach that i can check other application signature and public key. if Android OS guarantee that public key and signature is read-only and matched for installed application, i can rely on that and check public key of payment application before sending intent to that.but i guess those is not ready-only and check match only in installing.

any suggestion (similar or different approach) for prevent phishing attack ?

Updated: about 50% of application's user install application from my corporation website directly (Unknown-Source).

Mojtaba Asgari
  • 1,242
  • 1
  • 13
  • 24
  • I afraid that I understand your requirement or not. Please verify that I did it. You have a server and a client and wanted to verify that the server is actually yours and not any hacker during request/sending data to them. Am I correct?? – iamrameshkumar Apr 10 '16 at 12:30
  • @Ram No, i have an application that connect to payment application by service(aidl-implementation). i want to verify payment application before send my user to that. (actually both my application and payment application have server but my question not about verify them) – Mojtaba Asgari Apr 10 '16 at 13:09
  • 3
    The Android OS can give you a guarantee for public key verification before installing an application but that is also can be hacked easily if the user is not aware of the "avoid unknown sources settings",etc . Trusting an application is in the user's hands even if they are so careful on this, a compromised device would result in compromising the users data.You cannot expect the device to verify an application for each and every run once it is installed on the system. It all depends on the user and the OS settings.The data privacy is in the hands of application after installation – iamrameshkumar Apr 11 '16 at 16:33
  • 1
    You can use public key cryptography to verify whether the server is trusted or not from your application before sending the data. If your application itself is not trusted then it is not possible to save the client. The only way to make the users aware of the trust settings of unknown resources. – iamrameshkumar Apr 11 '16 at 16:34
  • @Ram "**The Android OS can give you a guarantee for public key verification before installing**" So any application can change their public key and signature after installation phase. Am i correct ? I'm expect that Android OS don't let application change their public key and signature after installation, this is not crazy work. – Mojtaba Asgari Apr 12 '16 at 04:49
  • @Ram public-key and signature of **APPLICATION**, in certificate segment of APK that you can access through PackageManager. So my problem is not about "trusting server with their public-key". – Mojtaba Asgari Apr 12 '16 at 05:00
  • @Ram if suppose that applications can change their public-key and signature in runtime then any intent or service communication is unsafe even if you set package name explicitly. (i don't known how they can change their public-key and signature in runtime but maybe crackers know !). – Mojtaba Asgari Apr 12 '16 at 05:13

3 Answers3

6

Android offers a native method to verify if an app has been installed from Play Store, even Amazon App Store. But does it work on other apps?

Take a look at the method:

PackageManager.getInstallerPackageName(String packageName) (Documentation)

Fortunately for you, getInstallerPackageName accepts a String package name, which means you can feed it your neighbor-app's package id, and have it return the package name that installed it!

This example will tell you if your neighbor-app was installed by Play Store, aka com.android.vending:

if(context.getPackageManager().getInstallerPackageName("com.untrusted.app") ==
  "com.android.vending") {                          //   ^^^ CHANGE ^^^

  //Verified; app installed directly from Play Store
}

Amazon app store has an odd package name:

if(context.getPackageManager().getInstallerPackageName("com.untrusted.app") ==
  "com.amazon.venezia") {

  //Verified; app installed directly from Amazon App Store
}

This should be everything you need, hope it helps!

Aaron Gillion
  • 2,227
  • 3
  • 19
  • 31
  • Thanks but i forget to say that about half of application's user install it directly. this is good idea to check installer. I use this idea but are you any suggestion for another users that install through unknown-source. – Mojtaba Asgari Apr 12 '16 at 08:37
  • @MojtabaAsg For those users who don't install directly, the `getInstallerPackageName` will return `null`. So just use `==null` in your `if` expression. – Aaron Gillion Apr 12 '16 at 08:39
  • So for those users we return to step 1, _how to verify this kind of application that installed from unknown source and we have only public-key and signature of application_. – Mojtaba Asgari Apr 12 '16 at 08:48
  • 1
    If you have a Signature, see [checkSignatures(java.lang.String, java.lang.String)](http://developer.android.com/reference/android/content/pm/PackageManager.html#checkSignatures(java.lang.String,%20java.lang.String)) – Aaron Gillion Apr 12 '16 at 08:52
  • exactly what i need, but wait! check documentation this API only check **both application signature is same!** that in my case is always false. if i have API from Android for checking public-key match with signature(for prevent fake public key) in runtime we can check their public-key and trust it. – Mojtaba Asgari Apr 12 '16 at 08:53
  • @MojtabaAsg It will always return false if you **don't own** both applications. – Aaron Gillion Apr 12 '16 at 08:55
  • exactly this is my case. – Mojtaba Asgari Apr 12 '16 at 08:57
4

What you are looking for is a combination of app signatures and permissions. To clarify, this will only work if you own both applications and can sign them with the same key.

According to the docs:

"signature": A permission that the system grants only if the requesting application is signed with the same certificate as the application that declared the permission. If the certificates match, the system automatically grants the permission without notifying the user or asking for the user's explicit approval.

This means that the Android OS itself enforces that the signatures of the two applications must match in order for the permission to be granted. This is what you want, since the permission will not be granted if someone tries to spoof your app. Since they cannot possibly sign their app with your private key, there is no way they can forge your signature.

To create a permission, in your Manifest for the application providing the payment service, you should declare it like this:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp.paymentservice" >

    <permission android:name="com.example.myapp.paymentservice.permission.PAYMENT"
        android:label="@string/permission_payment_label"
        android:description="@string/permission_payment_description"
        android:protectionLevel="signature" />
    ...

Then, when you declare your service, protect it with the android:permission that you declared:

    ...
    <service android:name=".BillingService"
        android:permission="com.example.myapp.paymentservice.permission.PAYMENT" />
</manifest>

Finally, you declare in your client application(s) that you use that permission:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp.clientapp" >

    <uses-permission android:name="com.example.myapp.paymentservice.permission.PAYMENT" />
    ...
</manifest>

As long as the two applications are signed with the same signing key, the OS will grant the permission. For more information, check out http://developer.android.com/guide/topics/security/permissions.html#defining and http://developer.android.com/guide/topics/manifest/permission-element.html

Jschools
  • 2,698
  • 1
  • 17
  • 18
3

What if main app get signature of payment app via package manager api and validate it (by whitlist of signatures, for example)? The validation process can also happened in main app server.

EDIT: somthing like that

        List<byte[]> whitelist = ... ; // load from config or something...

        PackageManager pm = this.getPackageManager();
        String packageName = "payment.app.package.name";

        PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
        Signature[] signatures = packageInfo.signatures;

        for (Signature sig : signatures) {
            InputStream input = new ByteArrayInputStream(sig.toByteArray());
            CertificateFactory cf = CertificateFactory.getInstance("X509");
            X509Certificate cert = (X509Certificate) cf.generateCertificate(input);

            PublicKey pb = cert.getPublicKey();
            if (! whitelist.contains(pb.getEncoded())) {
                throw new Exception("public key is not valid");
            }
        }
Daniel
  • 573
  • 6
  • 14
  • And if evil app can change their signature or add fake signature how can i detect it? – Mojtaba Asgari Apr 15 '16 at 20:30
  • The signature contains payment app public key. Payment app is installed, so it signed with matched private key. Assuming private key isn't stolen, evil app signature can't contain the public key in your whitelist – Daniel Apr 16 '16 at 20:22
  • @Daniel can you show us a code example? Or is it the same idea as Jschool's idea below? – Aaron Gillion Apr 16 '16 at 22:53
  • That is how to ckeck signature but if android protect application signatures after install from changing. – Mojtaba Asgari Apr 17 '16 at 04:30