Gestione sicura degli appunti

Categoria OWASP: MASVS-CODE: Code Quality

Panoramica

Android offre un framework potente chiamato clipboard per copiare e incollare dati tra le applicazioni. Un'implementazione errata di questa funzionalità potrebbe esporre i dati relativi all'utente ad applicazioni o aggressori di minacce non autorizzati.

Il rischio specifico associato all'esposizione dei dati della clipboard dipende dalla natura dell'applicazione e dalle informazioni che consentono l'identificazione personale (PII) che gestisce. L'impatto è particolarmente elevato per le applicazioni finanziarie, in quanto potrebbero esporre i dati di pagamento, o per le app che gestiscono i codici di autenticazione a due fattori (2FA).

I vettori di attacco che potrebbero essere sfruttati per esfiltrare i dati della clipboard variano a seconda della versione di Android:

  • Le versioni di Android precedenti ad Android 10 (livello API 29) consentono alle applicazioni in background di accedere alle informazioni della clipboard dell'app in primo piano, consentendo potenzialmente l'accesso diretto a tutti i dati copiati da parte di aggressori di minacce.
  • A partire da Android 12 (livello API 31), ogni volta che un'applicazione accede ai dati all'interno degli appunti e li incolla, all'utente viene mostrato un messaggio popup, il che rende più difficile che gli attacchi passino inosservati. Inoltre, per proteggere le PII, Android supporta il flag speciale ClipDescription.EXTRA_IS_SENSITIVE o android.content.extra.IS_SENSITIVE. In questo modo, gli sviluppatori possono oscurare visivamente l'anteprima dei contenuti della clipboard all'interno della GUI della tastiera, impedendo che i dati copiati vengano visualizzati in testo normale e potenzialmente rubati da applicazioni dannose. La mancata implementazione di uno dei flag sopra menzionati potrebbe consentire agli aggressori di esfiltrare i dati sensibili copiati nella clipboard tramite shoulder surfing o tramite applicazioni dannose che, mentre sono in esecuzione in background, acquisiscono screenshot o registrano video delle attività di un utente legittimo.

Impatto

Lo sfruttamento di una gestione errata della clipboard potrebbe comportare l'esfiltrazione di dati sensibili o finanziari relativi all'utente da parte di aggressori di minacce. Questo può aiutare gli aggressori a intraprendere ulteriori azioni, come campagne di phishing o furto di identità.

Mitigazioni

Contrassegnare i dati sensibili

Questa soluzione viene utilizzata per oscurare visivamente l'anteprima dei contenuti della clipboard all'interno della GUI della tastiera. Prima di chiamare ClipboardManager.setPrimaryClip(), tutti i dati sensibili che possono essere copiati, come password o dati della carta di credito, devono essere contrassegnati con ClipDescription.EXTRA_IS_SENSITIVE o android.content.extra.IS_SENSITIVE.

Kotlin

// 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)
    }
}

Java

// 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);

Applicare le versioni più recenti di Android

Se l'app viene eseguita su versioni di Android successive o uguali ad Android 10 (API 29), i processi in background non possono accedere ai dati della clipboard nell'applicazione in primo piano.

Per forzare l'esecuzione dell'app solo su Android 10 (API 29) o versioni successive, imposta i seguenti valori per le impostazioni della versione nei file di build Gradle all'interno del progetto in Android Studio.

Alla moda

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

Kotlin

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

Eliminare i contenuti della clipboard dopo un periodo di tempo definito

Se l'applicazione è progettata per essere eseguita su versioni di Android precedenti ad Android 10 (livello API 29), qualsiasi applicazione in background può accedere ai dati della clipboard. Per ridurre questo rischio, è utile implementare una funzione che cancelli tutti i dati copiati nella clipboard dopo un periodo di tempo specifico. Questa funzione viene eseguita automaticamente a partire da Android 13 (livello API 33). Per le versioni precedenti di Android, questa eliminazione può essere eseguita includendo il seguente snippet nel codice dell'applicazione.

Kotlin

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

Java

//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);

Risorse