Перейти к содержанию

Небезопасная передача sensitive-информации в Activity

Критичность: КРИТИЧНЫЙ
Способ обнаружения: DAST, SENSITIVE INFO

Описание

Приложение включает чувствительную информацию в неявный Intent для запуска Activity. Это может привести к перехвату этой информации сторонними приложениями.

Межпроцессное взаимодействие (IPC) в Android осуществляться при помощи специальных объектов — Intent. Параметры обработчиков Intent задаются в основной файле манифеста приложения — AndroidManifest.xml либо, в случае с динамическими BroadcastReceivers, в коде приложения. Если используются неявные Intent, такие Intent не содержат имени конкретного компонента, вместо этого они в целом объявляют действие, которое требуется выполнить, что дает возможность компоненту из другого приложения обработать этот запрос. Например, если требуется показать пользователю место на карте, то с помощью неявного объекта Intent можно запросить, чтобы это сделало другое приложение, в котором такая возможность предусмотрена. Данные, содержащиеся в таких сообщениях, могут быть скомпрометированы. Кроме того, вредоносными приложениями могут использоваться механизмы делегирования управления процессами, такие как неявные вызовы компонентов приложений или объекты типа PendingIntent, для перехвата потока управления и фишинговых атак.

Опасность представляют объекты типов Activity, Service, BroadcastReceiver и ContentProvider, открытые для взаимодействия с другими приложениями и не относящиеся к системным Android-вызовам (таким как android.intent.action.MAIN). BroadcastReceiver по умолчанию открыт для взаимодействия с другими приложениями, в таком случае возможен перехват Intent с конфиденциальной информацией или перехват управления.

Рекомендации

При использовании неявных Intent (когда пользователь сам определяет, какое приложение должно обработать сообщение) нельзя включать sensitive-информацию в параметры.

Риски при использовании Activity и соответствующие им защитные меры различаются в зависимости от того, как используется эта Activity. Мы выделяем 4 типа Activity в зависимости от способов использования. Для определения типа Activity, которую планируется создавать, необходимо воспользоваться таблицей и диаграммой, представленными ниже.

Создание и использование Public Activity

В качестве примера будет разобран процесс создания и использования Public Activity.

Public Activity — это Activity, которая может быть использована любым сторонним приложением. Необходимо понимать, что:

  • Public Activity может получить Intent из вредоносного приложения.
  • Вредоносное приложение может получить Intent, отправленный в Public Activity и/или считывать из него данные.

Правила (создание Public Activity):

  1. Явно указывайте атрибут exported="true".

  2. Проводите проверку и безопасную обработку полученного Intent.

  3. Не включайте в Intent результата чувствительную информацию.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.appsec.android.activity.publicactivity" >
<application
android:allowBackup="false"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<!-- Public Activity -->
<!-- *** 1 *** Явно указывайте атрибут exported="true" -->
<activity
android:name=".PublicActivity"
android:label="@string/app_name"
android:exported="true">
<!-- Обьявление intent фильтра для получения неявных Intent'ов с определённым Action -->
<intent-filter>
<action android:name="com.appsec.android.activity.MY_ACTION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>

PublicActivity.java

package com.appsec.android.activity.publicactivity;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class PublicActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // *** 2 *** Проводите проверку и безопасную обработку полученного Intent
        // Т.к. это Public Activity, то возможно что отправителем Intent'a является вредоносное приложение
        // См.п. "Безопасная обработка входных данных"

        String param = getIntent().getStringExtra("PARAM");
        Toast.makeText(this, String.format("Received param: \"%s\"", param), Toast.LENGTH_LONG).show();
    }
    public void onReturnResultClick(View view) {

        // *** 3 *** Не включайте в Intent результата чувствительную информацию
        // Т.к. это Public Activity, то возможно что получателем Intent'a будет вредоносное приложение
        Intent intent = new Intent();
        intent.putExtra("RESULT", "Not Sensitive Info");
        setResult(RESULT_OK, intent);
        finish();
    }
}

Правила (использование Public Activity):

  1. Не включайте конфиденциальную информацию в Intent, используемый для запуска Activity;

  2. Проводите проверку и безопасную обработку полученных данных результата;

PublicUserActivity.java

package com.appsec.android.activity.publicuser;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class PublicUserActivity extends Activity {
    private static final int REQUEST_CODE = 1;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    public void onUseActivityClick(View view) {

        try {
            // *** 1 *** Не включайте конфиденциальную информацию в Intent, используемый для запуска Activity
            Intent intent = new Intent("org.jssec.android.activity.MY_ACTION");
            intent.putExtra("PARAM", "Not Sensitive Info");
            startActivityForResult(intent, REQUEST_CODE);
        } catch (ActivityNotFoundException e) {
            Toast.makeText(this, "Target activity not found.", Toast.LENGTH_LONG).show();
        }
    }
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        // *** 2 *** Проводите проверку и безопасную обработку полученных данных результата
        // См.п. "Безопасная обработка входных данных"

        if (resultCode != RESULT_OK) return;
        switch (requestCode) {
        case REQUEST_CODE:
            String result = data.getStringExtra("RESULT");
            Toast.makeText(this, String.format("Received result: \"%s\"", result), Toast.LENGTH_LONG).show();
            break;
        }
    }
}

Также при использовании неявных Intent будьте внимательны!

Внимание!

Возможна ситуация, когда на устройстве пользователя не будет никакого приложения, которое может откликнуться на неявный объект Intent, отправленный вами методу startActivity(). В этом случае вызов закончится неудачей, а работа приложения аварийно завершится. Чтобы проверить, будет получен ли операцией объект Intent, вызовите метод resolveActivity() для своего объекта Intent. Если результатом будет значение, отличное от null, значит, имеется хотя бы одно приложение, которое способно откликнуться на объект Intent и можно вызывать startActivity(). Если же результатом будет значение null, объект Intent не следует использовать и по возможности следует отключить функцию, которая выдает этот объект Intent.

Ссылки

  1. https://developer.android.com/guide/components/intents-filters?hl=ru

  2. https://github.com/OWASP/owasp-mstg/blob/master/Document/0x05h-Testing-Platform-Interaction.md

  3. https://developer.android.com/training/basics/intents/index.html

К началу