Безопасная обработка буфера обмена

Категория OWASP: MASVS-CODE: Качество кода

Обзор

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

Конкретный риск, связанный с раскрытием данных буфера обмена, зависит от характера приложения и информации, позволяющей установить личность (PII), которую оно обрабатывает. Влияние особенно велико для финансовых приложений, поскольку они могут раскрывать платежные данные или приложения, обрабатывающие коды двухфакторной аутентификации (2FA).

Векторы атак, которые можно использовать для кражи данных буфера обмена, различаются в зависимости от версии Android:

  • Версии Android старше Android 10 (уровень API 29) позволяют фоновым приложениям получать доступ к информации буфера обмена приложения на переднем плане, что потенциально обеспечивает злоумышленникам прямой доступ к любым скопированным данным.
  • Начиная с Android 12 (уровень API 31), каждый раз, когда приложение обращается к данным в буфере обмена и вставляет их, пользователю отображается всплывающее сообщение, что затрудняет возможность остаться незамеченными атакам. Кроме того, для защиты личных данных Android поддерживает специальный флаг ClipDescription.EXTRA_IS_SENSITIVE или android.content.extra.IS_SENSITIVE . Это позволяет разработчикам визуально запутывать предварительный просмотр содержимого буфера обмена в графическом интерфейсе клавиатуры, предотвращая визуальное отображение скопированных данных в виде открытого текста и их потенциальную кражу вредоносными приложениями. Отсутствие одного из вышеупомянутых флагов фактически может позволить злоумышленникам получить конфиденциальные данные, скопированные в буфер обмена, либо путем серфинга, либо через вредоносные приложения, которые во время работы в фоновом режиме делают снимки экрана или записывают видео действий законного пользователя.

Влияние

Использование неправильной обработки буфера обмена может привести к краже конфиденциальных или финансовых данных пользователей злоумышленниками. Это может помочь злоумышленникам в проведении дальнейших действий, таких как фишинговые кампании или кража личных данных.

Смягчения

Пометить конфиденциальные данные

Это решение используется для визуального запутывания предварительного просмотра содержимого буфера обмена в графическом интерфейсе клавиатуры. Любые конфиденциальные данные, которые можно скопировать, например пароли или данные кредитной карты, следует пометить с помощью ClipDescription.EXTRA_IS_SENSITIVE или android.content.extra.IS_SENSITIVE перед вызовом ClipboardManager.setPrimaryClip() .

Котлин

// If your app is compiled with the API level 33 SDK or higher.
clipData.apply {
    description.extras = PersistableBundle().apply {
        putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true)
    }
}

// If your app is compiled with API level 32 SDK or lower.
clipData.apply {
    description.extras = PersistableBundle().apply {
        putBoolean("android.content.extra.IS_SENSITIVE", true)
    }
}

Ява

// If your app is compiled with the API level 33 SDK or higher.
PersistableBundle extras = new PersistableBundle();
extras.putBoolean(ClipDescription.EXTRA_IS_SENSITIVE, true);
clipData.getDescription().setExtras(extras);

// If your app is compiled with API level 32 SDK or lower.
PersistableBundle extras = new PersistableBundle();
extras.putBoolean("android.content.extra.IS_SENSITIVE", true);
clipData.getDescription().setExtras(extras);

Применять последние версии Android

Принудительный запуск приложения на версиях Android более поздних или равных Android 10 (API 29) не позволяет фоновым процессам получать доступ к данным буфера обмена в приложении переднего плана.

Чтобы приложение работало только на Android 10 (API 29) или более поздней версии, установите следующие значения для параметров версии в файлах сборки Gradle в вашем проекте в Android Studio.

классный

android {
      namespace 'com.example.testapp'
      compileSdk [SDK_LATEST_VERSION]

      defaultConfig {
          applicationId "com.example.testapp"
          minSdk 29
          targetSdk [SDK_LATEST_VERSION]
          versionCode 1
          versionName "1.0"
          ...
      }
      ...
    }
    ...

Котлин

android {
      namespace = "com.example.testapp"
      compileSdk = [SDK_LATEST_VERSION]

      defaultConfig {
          applicationId = "com.example.testapp"
          minSdk = 29
          targetSdk = [SDK_LATEST_VERSION]
          versionCode = 1
          versionName = "1.0"
          ...
      }
      ...
    }
    ...

Удалить содержимое буфера обмена через определенный период времени

Если приложение предназначено для работы на версиях Android ниже Android 10 (уровень API 29), любое фоновое приложение может получить доступ к данным буфера обмена. Чтобы снизить этот риск, полезно реализовать функцию, которая очищает любые данные, скопированные в буфер обмена, через определенный период времени. Эта функция автоматически выполняется, начиная с Android 13 (уровень API 33) . В более старых версиях Android это удаление можно выполнить, включив следующий фрагмент в код приложения.

Котлин

//The Executor makes this task Asynchronous so that the UI continues being responsive
backgroundExecutor.schedule({
    //Creates a clip object with the content of the Clipboard
    val clipboard = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
    val clip = clipboard.primaryClip
    //If SDK version is higher or equal to 28, it deletes Clipboard data with clearPrimaryClip()
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        clipboard.clearPrimaryClip()
    } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
    //If SDK version is lower than 28, it will replace Clipboard content with an empty value
        val newEmptyClip = ClipData.newPlainText("EmptyClipContent", "")
        clipboard.setPrimaryClip(newEmptyClip)
     }
//The delay after which the Clipboard is cleared, measured in seconds
}, 5, TimeUnit.SECONDS)

Ява

//The Executor makes this task Asynchronous so that the UI continues being responsive

ScheduledExecutorService backgroundExecutor = Executors.newSingleThreadScheduledExecutor();

backgroundExecutor.schedule(new Runnable() {
    @Override
    public void run() {
        //Creates a clip object with the content of the Clipboard
        ClipboardManager clipboard = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);
        ClipData clip = clipboard.getPrimaryClip();
        //If SDK version is higher or equal to 28, it deletes Clipboard data with clearPrimaryClip()
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            clipboard.clearPrimaryClip();
            //If SDK version is lower than 28, it will replace Clipboard content with an empty value
        } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
            ClipData newEmptyClip = ClipData.newPlainText("EmptyClipContent", "");
            clipboard.setPrimaryClip(newEmptyClip);
        }
    //The delay after which the Clipboard is cleared, measured in seconds
    }, 5, TimeUnit.SECONDS);

Ресурсы