Как проверить установленное приложение во время выполнения, чтобы предотвратить фишинговую атаку?

У меня есть платежное приложение на моем устройстве, мое приложение подключается к службе этого приложения, чтобы получить ожидающее намерение для запуска платежной операции, а затем прослушивать результат в методе onActivityResult() (аналогично сценарию In-App-Purchase)

Я установил имя пакета для платежного намерения. но вы знаете, это не гарантия того, что платежному приложению доверяют. если кто-то установит поддельное приложение из неизвестного источника с тем же именем пакета и той же реализацией службы помощи, то это может дать мне ожидающее намерение и фишинг моей информации о пользователе.

Я проверяю результат платежа с помощью некоторого механизма, и это только защищает мое приложение от поддельного результата платежа, но пользователь моего приложения вводит свои данные в фишерское приложение. (в этом абзаце говорится, что моя проблема заключается в том, что я не доверяю ответу платежного приложения, < strong>моя проблема заключается в том, что я доверяю платежному приложению перед тем, как начать свою деятельность)

Я знаю какой-то подход, с помощью которого я могу проверить подпись другого приложения и открытый ключ. если ОС Android гарантирует, что открытый ключ и подпись доступны только для чтения и совпадают с установленным приложением, я могу положиться на это и проверить открытый ключ платежного приложения перед отправкой намерения этому .но я предполагаю, что они не только готовы и проверяют совпадение только при установке.

любое предложение (аналогичный или другой подход) для предотвращения фишинговой атаки?

Обновлено: около 50% пользователей приложения устанавливают приложение непосредственно с веб-сайта моей корпорации (неизвестный источник).


person Mojtaba Asg    schedule 06.04.2016    source источник
comment
Боюсь, я понимаю ваше требование или нет. Пожалуйста, подтвердите, что я это сделал. У вас есть сервер и клиент, и вы хотели убедиться, что сервер действительно ваш, а не какой-то хакер, во время запроса/отправки им данных. Я прав??   -  person iamrameshkumar    schedule 10.04.2016
comment
@Ram Нет, у меня есть приложение, которое подключается к платежному приложению с помощью службы (aidl-implementation). я хочу проверить платежное приложение, прежде чем отправить моего пользователя на него. (на самом деле и мое приложение, и платежное приложение имеют сервер, но мой вопрос не о том, чтобы проверить их)   -  person Mojtaba Asg    schedule 10.04.2016
comment
ОС Android может дать вам гарантию проверки открытого ключа перед установкой приложения, но ее также можно легко взломать, если пользователь не знает о настройках избегания неизвестных источников и т. д. Доверие к приложению находится в руках пользователя, даже если он настолько осторожен в этом, скомпрометированное устройство приведет к компрометации данных пользователя. Нельзя ожидать, что устройство будет проверять приложение для каждого запуска после его установки в системе. Все зависит от пользователя и настроек ОС. Конфиденциальность данных находится в руках приложения после установки   -  person iamrameshkumar    schedule 11.04.2016
comment
Вы можете использовать криптографию с открытым ключом, чтобы проверить, является ли сервер доверенным или нет, из вашего приложения перед отправкой данных. Если само ваше приложение не является доверенным, то невозможно сохранить клиент. Единственный способ сообщить пользователям о настройках доверия неизвестных ресурсов.   -  person iamrameshkumar    schedule 11.04.2016
comment
@Ram ОС Android может гарантировать вам проверку открытого ключа перед установкой Таким образом, любое приложение может изменить свой открытый ключ и подпись после этапа установки. Я прав ? Я ожидаю, что ОС Android не позволяет приложению менять свой открытый ключ и подпись после установки, это не сумасшедшая работа.   -  person Mojtaba Asg    schedule 12.04.2016
comment
Открытый ключ @Ram и подпись APPLICATION в сегменте сертификата APK, к которому вы можете получить доступ через PackageManager. Так что моя проблема не в том, чтобы доверять серверу их открытый ключ.   -  person Mojtaba Asg    schedule 12.04.2016
comment
@Ram, если предположить, что приложения могут изменять свой открытый ключ и подпись во время выполнения, тогда любое намерение или связь службы небезопасны, даже если вы явно задаете имя пакета. (я не знаю, как они могут изменить свой открытый ключ и подпись во время выполнения, но, возможно, взломщики знают!).   -  person Mojtaba Asg    schedule 12.04.2016


Ответы (3)


Android предлагает собственный метод проверки того, было ли установлено приложение из Play Store, даже из Amazon App Store. Но работает ли это в других приложениях?

Взгляните на метод:

PackageManager.getInstallerPackageName(String packageName) (Документация)

К счастью для вас, getInstallerPackageName принимает имя пакета String, что означает, что вы можете передать ему идентификатор пакета вашего соседнего приложения, и он вернет имя пакета, который его установил!

Этот пример покажет вам, было ли ваше соседнее приложение установлено Play Store, также известным как com.android.vending:

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

  //Verified; app installed directly from Play Store
}

Магазин приложений Amazon имеет странное название пакета:

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

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

Это должно быть все, что вам нужно, надеюсь, это поможет!

person Aaron Gillion    schedule 12.04.2016
comment
Спасибо, но я забыл сказать, что около половины пользователей приложения устанавливают его напрямую. это хорошая идея, чтобы проверить установщик. Я использую эту идею, но вы можете предложить другим пользователям установку через неизвестный источник. - person Mojtaba Asg; 12.04.2016
comment
@MojtabaAsg Для тех пользователей, которые не устанавливают напрямую, getInstallerPackageName вернет null. Так что просто используйте ==null в выражении if. - person Aaron Gillion; 12.04.2016
comment
Поэтому для этих пользователей мы возвращаемся к шагу 1, как проверить приложение такого типа, которое установлено из неизвестного источника, и у нас есть только открытый ключ и подпись приложения. - person Mojtaba Asg; 12.04.2016
comment
именно то, что мне нужно, но подождите! проверьте документацию этого API только проверьте подпись обоих приложений одинакова! что в моем случае всегда неверно. если у меня есть API от Android для проверки совпадения открытого ключа с подписью (для предотвращения поддельного открытого ключа) во время выполнения, мы можем проверить их открытый ключ и доверять ему. - person Mojtaba Asg; 12.04.2016
comment
@MojtabaAsg Всегда будет возвращать false, если вы не владеете обоими приложениями. - person Aaron Gillion; 12.04.2016
comment
именно это мой случай. - person Mojtaba Asg; 12.04.2016

Что, если основное приложение получит подпись платежного приложения через API-интерфейс менеджера пакетов и проверит ее (например, по белому списку подписей)? Процесс проверки также может происходить на главном сервере приложений.

РЕДАКТИРОВАТЬ: что-то в этом роде

        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");
            }
        }
person Daniel    schedule 14.04.2016
comment
И если злое приложение может изменить свою подпись или добавить поддельную подпись, как я могу это обнаружить? - person Mojtaba Asg; 15.04.2016
comment
Подпись содержит открытый ключ платежного приложения. Платежное приложение установлено, поэтому оно подписано совпадающим закрытым ключом. Предполагая, что закрытый ключ не украден, сигнатура вредоносного приложения не может содержать открытый ключ в вашем белом списке. - person Daniel; 16.04.2016
comment
@Daniel, можешь показать нам пример кода? Или это та же идея, что и идея Jschool ниже? - person Aaron Gillion; 17.04.2016
comment
Вот как проверить подпись, но если Android защищает подписи приложений после установки от изменения. - person Mojtaba Asg; 17.04.2016

То, что вы ищете, — это комбинация подписей приложений и разрешений. Чтобы уточнить, это будет работать только в том случае, если вы владеете обоими приложениями и можете подписывать их одним и тем же ключом.

Согласно документам:

«signature»: разрешение, которое система предоставляет, только если запрашивающее приложение подписано тем же сертификатом, что и приложение, объявившее разрешение. Если сертификаты совпадают, система автоматически предоставляет разрешение, не уведомляя пользователя и не запрашивая явное согласие пользователя.

Это означает, что сама ОС Android требует, чтобы подписи двух приложений совпадали, чтобы разрешение было предоставлено. Это то, что вам нужно, поскольку разрешение не будет предоставлено, если кто-то попытается подделать ваше приложение. Поскольку они не могут подписать свое приложение с помощью вашего закрытого ключа, они не смогут подделать вашу подпись.

Чтобы создать разрешение, в своем манифесте для приложения, предоставляющего платежную услугу, вы должны объявить его следующим образом:

<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

person Jschools    schedule 15.04.2016
comment
Это полезно, означает ли это, что вы владеете (вы подписываете) обоими приложениями? - person Aaron Gillion; 16.04.2016
comment
Но мое приложение хочет доверять стороннему приложению, которое не является моим - person Mojtaba Asg; 17.04.2016
comment
Я не знал, что у вас нет платежного приложения. В этом случае разрешения не будут работать для вас, извините. Код Дэниела может быть тем, что вы ищете. - person Jschools; 18.04.2016