Verifica delle dipendenze

Le dipendenze Gradle compromesse rappresentano un rischio per la sicurezza. Un utente malintenzionato potrebbe potenzialmente iniettare una dipendenza modificata nel processo di compilazione, ad esempio tramite un attacco man-in-the-middle durante la risoluzione delle dipendenze.

Se una dipendenza di compilazione (una libreria) è stata compromessa, può influire sul modo in cui la tua applicazione viene eseguita su un dispositivo. Se la dipendenza di un plug-in è stata compromessa, può cambiare il funzionamento della compilazione o persino eseguire comandi esterni sulla macchina di compilazione.

Per mitigare il problema, puoi attivare la verifica delle dipendenze nella compilazione.

Controlli di congruenza e firme delle librerie

Gli autori delle librerie possono fornire due metadati che possono aiutarti a verificare l'autenticità delle dipendenze che stai scaricando. Definisci un file denominato gradle/verification-metadata.xml per specificare i valori che approvi. Può contenere:

  • Checksum: un hash di un elemento che puoi utilizzare per verificare che l'elemento non sia stato danneggiato durante il trasporto. Se il checksum è stato recuperato da una fonte attendibile, ti viene comunicato che l'elemento non è cambiato, riducendo gli attacchi man-in-the-middle.

    Il rovescio della medaglia è che, poiché i checksum vengono calcolati dagli elementi, cambiano con ogni release, pertanto devi aggiornare gradle/verification-metadata.xml ogni volta che esegui l'upgrade.

  • Firme: consente agli utenti delle dipendenze di specificare una chiave pubblica per un determinato elemento per convalidare che questo elemento sia stato creato e firmato dall'autore della libreria, che è il proprietario autenticato della chiave pubblica. Questo comporta un maggiore impegno per l'autore della libreria, ma a condizione che la chiave privata stessa non sia stata compromessa, la firma indica che la libreria è legittima.

    Se l'autore della libreria firma ogni versione di un elemento con la stessa chiave, non devi aggiornare gradle/verification-metadata.xml quando lo aggiorni.

Attiva la verifica delle dipendenze

La verifica delle dipendenze di Gradle confronta i checksum e le firme durante la compilazione.

Crea un file gradle/verification-metadata.xml contenente quanto segue:

<?xml version="1.0" encoding="UTF-8"?>
<verification-metadata
    xmlns="https://schema.gradle.org/dependency-verification"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="https://schema.gradle.org/dependency-verification https://schema.gradle.org/dependency-verification/dependency-verification-1.3.xsd">
    <configuration>
        <!-- verify .pom and .module files -->
        <verify-metadata>true</verify-metadata>
        <!-- verify .asc PGP files that come with the artifacts -->
        <verify-signatures>true</verify-signatures>
        <!-- use human readable keyring format -->
        <keyring-format>armored</keyring-format>
        <!-- read keys in a local file, fewer requests to network -->
        <key-servers enabled="false">
            <key-server uri="https://keyserver.ubuntu.com"/>
            <key-server uri="https://keys.openpgp.org"/>
        </key-servers>
    </configuration>
    <components>
    </components>
</verification-metadata>

Questo è un punto di partenza e verrà aggiornato a breve.

Esegui ./gradlew assembleDebug per vedere in che modo questa modifica la compilazione. Visualizzerai messaggi come

* What went wrong:
Error resolving plugin [id: 'com.android.application', version: '8.7.3', apply: false]
> Dependency verification failed for configuration 'detachedConfiguration1'
  One artifact failed verification: com.android.application.gradle.plugin-8.7.3.pom ...
  This can indicate that a dependency has been compromised ...
  
  Open this report for more details: .../dependency-verification-report.html

Gradle ti sta comunicando che stai importando versioni di dipendenze che non hai approvato esplicitamente.

Esegui il bootstrap dei dati di checksum e firma

Puoi avviare il bootstrap dei componenti e delle chiavi attendibili impostati inizialmente. Questa procedura raccoglie le firme e i checksum correnti per tutte le librerie utilizzate dal progetto.

Genera i metadati iniziali eseguendo

./gradlew --write-verification-metadata pgp,sha256 --export-keys help

Questo comando indica a Gradle di creare un elenco di chiavi PGP e checksum di riserva per tutte le dipendenze utilizzate in questo progetto. Noterai una modifica al file verification-metadata.xml con una serie di voci come:

<trusted-key id="8461EFA0E74ABAE010DE66994EB27DB2A3B88B8B">
    <trusting group="androidx.activity"/>
</trusted-key>

Questo indica a Gradle che, se rileva una dipendenza dal gruppo Mavenandroidx.activity, deve assicurarsi che i file .asc associati (le firme memorizzate nel repository) corrispondano a quella chiave.

Il bootstrapping genererà anche gradle/verification-keyring.keys che contiene le chiavi PGP pubbliche utilizzate dalla build. Esegui il check-in di entrambi i file nel tuo sistema di monitoraggio delle versioni. Eventuali modifiche future che modificano verification-metadata.xml o verification-keyring.keys devono essere esaminate attentamente.

Rimuovi le versioni dalle chiavi attendibili

Le chiavi di firma raramente cambiano tra le release di una libreria. I dati generati nel file gradle/verification-metadata.xml contengono i dettagli della versione, il che significa che dovrai aggiungere di nuovo le informazioni chiave per ogni nuova versione della dipendenza.

Per evitare questo problema e specificare che la chiave si applica a tutte le versioni di una libreria,rimuovi le specifiche della versione.

Nell'editor di Android Studio, utilizza Modifica > Trova > Sostituisci… utilizzando un'espressione regolare per sostituire tutte le specifiche della versione per le chiavi attendibili.

  • da: <trusted-key(.*) version=\".*\"/>
  • a: <trusted-key$1/>

Sincronizzazione di Android Studio

Finora la compilazione a riga di comando funziona, ma se provi a eseguire la sincronizzazione in Android Studio vedrai errori come

A build operation failed.
    Dependency verification failed for configuration ':app:detachedConfiguration3'
One artifact failed verification: gradle-8.10.2-src.zip (gradle:gradle:8.10.2) from repository Gradle distributions
If the artifacts are trustworthy, you will need to update the gradle/verification-metadata.xml file. For more on how to do this, please refer to https://docs.gradle.org/8.10.2/userguide/dependency_verification.html#sec:troubleshooting-verification in the Gradle documentation.

Android Studio vuole scaricare i sorgenti di Gradle (insieme ad altre fonti e documenti). Il modo più semplice per correggere il problema è considerare attendibili tutti i file sorgente e Javadoc. Aggiungi <trusted-artifacts> nel seguente paese: gradle/verification-metadata.xml

<verification-metadata ...>
   <configuration>
      <trusted-artifacts>
         <trust file=".*-javadoc[.]jar" regex="true"/>
         <trust file=".*-sources[.]jar" regex="true"/>
         <trust group="gradle" name="gradle"/>
      </trusted-artifacts>
      ...
  </configuration>
</verification-metadata>

Ora la build funzionerà correttamente dalla riga di comando e da Android Studio.