如何在运行时validation已安装的应用程序以防止钓鱼攻击?

我的设备中有一个支付应用程序,我的应用程序连接到该应用程序的服务,以获得启动支付活动的待定意图,然后在onActivityResult()方法中收听结果(类似于应用程序内购买场景)

我为付款意向设置了包名称。 但是你知道,这不是担保支付应用程序是可信的。 如果有人用相同包名和相同的aidl-service实现通过未知来源安装假应用程序,那么它可以给我等待意图和钓鱼我的用户信息。

我使用某种机制validation付款结果,并且只保护我的应用程序免受虚假付款结果,但我的应用程序用户将其数据input到phisher应用程序中。 (这段话说我的问题不是信任支付应用程序的回应, 我的问题是在开展他们的活动之前相信支付应用程序

我知道一些方法,我可以检查其他应用程序的签名和公钥。 如果 Android操作系统保证公共密钥和签名是只读的并且与已安装的应用程序匹配 ,我可以依靠它并在发送意图之前检查支付应用程序的公共密钥。但是我想这些只是没有准备就绪,只匹配检查在安装。

任何build议(类似或不同的方法),以防止networking钓鱼攻击?

更新 :约50%的应用程序的用户从我的公司网站直接安装应用程序(未知来源)。

Solutions Collecting From Web of "如何在运行时validation已安装的应用程序以防止钓鱼攻击?"

Android提供了一种本地方法来validation是否已经从Play商店,甚至Amazon App Store安装了应用程序。 但它在其他应用程序上工作吗?

看看这个方法:

PackageManager.getInstallerPackageName(String packageName) (Documentation)

幸运的是, getInstallerPackageName接受一个String包的名字,这意味着你可以给它的邻居应用的包id,并让它返回安装它的包名!

这个例子会告诉你,如果你的邻居应用程序是由Play商店安装的,又名com.android.vending

 if(context.getPackageManager().getInstallerPackageName("com.untrusted.app") == "com.android.vending") { // ^^^ CHANGE ^^^ //Verified; app installed directly from Play Store } 

亚马逊app store有一个奇怪的包名称:

 if(context.getPackageManager().getInstallerPackageName("com.untrusted.app") == "com.amazon.venezia") { //Verified; app installed directly from Amazon App Store } 

这应该是你需要的一切,希望它有帮助!

如果主要应用程序通过包pipe理器api获得支付应用程序的签名并validation它(例如通过签名的whitlist)? validation过程也可能发生在主应用服务器上。

编辑:这样的东西

  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"); } } 

你正在寻找的是应用程序签名和权限的组合。 为了澄清,只有当您拥有这两个应用程序并且可以使用相同的密钥签名时,这才会起作用。

根据文件:

“签名”:系统只有在请求应用程序使用与声明权限的应用程序相同的证书进行签名时才授予的权限。 如果证书匹配,则系统自动授予权限而不通知用户或要求用户明确批准。

这意味着Android操作系统本身强制两个应用程序的签名必须匹配才能授予权限。 这是你想要的,因为如果有人试图欺骗你的应用程序将不会授予权限。 由于他们不可能使用您的私钥签署他们的应用程序,他们无法伪造您的签名。

要创build一个权限,在你的提供付款服务的应用程序的清单中,你应该这样声明:

 <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" /> ... 

然后,当你声明你的服务时,用你声明的android:permission保护它:

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

最后,您在客户端应用程序中声明您使用该权限:

 <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> 

只要这两个应用程序使用相同的签名密钥签名,操作系统将授予该权限。 有关更多信息,请查看http://developer.android.com/guide/topics/security/permissions.html#defining和http://developer.android.com/guide/topics/manifest/permission-element.html