Categoria OWASP: MASVS-NETWORK: Network Communication
Panoramica
DownloadManager è un servizio di sistema introdotto nel livello API 9. Gestisce i download HTTP a lunga esecuzione e consente alle applicazioni di scaricare file come attività in background. La sua API gestisce le interazioni HTTP e riprova i download dopo errori o in caso di modifiche alla connettività e riavvii del sistema.
DownloadManager presenta punti deboli rilevanti per la sicurezza che lo rendono una scelta non sicura per la gestione dei download nelle applicazioni per Android.
(1) CVE nel fornitore di download
Nel 2018, sono state trovate e corrette tre CVE in Download Provider. Di seguito è riportato un riepilogo di ciascuna (vedi dettagli tecnici).
- Elusione dell'autorizzazione del provider di download: senza autorizzazioni concesse, un'app dannosa potrebbe recuperare tutte le voci dal provider di download, che potrebbero includere informazioni potenzialmente sensibili come nomi, descrizioni, titoli, percorsi, URL, nonché autorizzazioni di LETTURA/SCRITTURA complete per tutti i file scaricati. Un'app dannosa potrebbe essere eseguita in background, monitorando tutti i download e divulgando i relativi contenuti da remoto o modificando i file al volo prima che vengano aperti dal richiedente legittimo. Ciò potrebbe causare un attacco denial of service per l'utente per le applicazioni principali, inclusa l'impossibilità di scaricare gli aggiornamenti.
- SQL injection del provider di download: tramite una vulnerabilità SQL injection, un'applicazione dannosa senza autorizzazioni potrebbe recuperare tutte le voci dal provider di download. Inoltre, le applicazioni con autorizzazioni limitate, ad esempio
android.permission.INTERNET, potrebbero accedere anche a tutti i contenuti del database da un URI diverso. Potrebbero essere recuperate informazioni potenzialmente sensibili come nomi, descrizioni, titoli, percorsi e URL dei file e, a seconda delle autorizzazioni, potrebbe essere possibile accedere anche ai contenuti scaricati. - Divulgazione di informazioni sulle intestazioni delle richieste del fornitore di download: un'applicazione
dannosa con l'autorizzazione
android.permission.INTERNETconcessa potrebbe recuperare tutte le voci dalla tabella delle intestazioni delle richieste del fornitore di download. Queste intestazioni possono includere informazioni sensibili, come cookie di sessione o intestazioni di autenticazione, per qualsiasi download avviato da Android Browser o Google Chrome, tra le altre applicazioni. Ciò potrebbe consentire a un malintenzionato di impersonare l'utente su qualsiasi piattaforma da cui sono stati ottenuti dati utente sensibili.
(2) Autorizzazioni pericolose
DownloadManager nei livelli API inferiori a 29 richiede autorizzazioni pericolose:
android.permission.WRITE_EXTERNAL_STORAGE. Per il livello API 29
e versioni successive, le autorizzazioni android.permission.WRITE_EXTERNAL_STORAGE non sono richieste, ma l'URI deve fare riferimento a un percorso all'interno delle directory di proprietà dell'applicazione o a un percorso all'interno della directory "Download" di primo livello.
(3) Reliance on Uri.parse()
DownloadManager si basa sul metodo Uri.parse() per analizzare la posizione del
download richiesto. Nell'interesse delle prestazioni, la classe Uri applica
una convalida minima o nulla all'input non attendibile.
Impatto
L'utilizzo di DownloadManager può portare a vulnerabilità attraverso lo sfruttamento delle autorizzazioni di scrittura nella memoria esterna. Poiché le autorizzazioni android.permission.WRITE_EXTERNAL_STORAGE consentono un ampio accesso allo spazio di archiviazione esterno, un malintenzionato può modificare silenziosamente file e download, installare app potenzialmente dannose, negare il servizio alle app principali o causare l'arresto anomalo delle app. Gli autori di attacchi potrebbero anche manipolare ciò che viene inviato a Uri.parse() per indurre l'utente a scaricare un file dannoso.
Mitigazioni
Anziché utilizzare DownloadManager, configura i download direttamente nella tua app utilizzando un client HTTP (ad esempio Cronet), un pianificatore/gestore di processi e un modo per garantire i tentativi in caso di perdita di rete. La documentazione della libreria include un link a un'app di esempio e istruzioni su come implementarla.
Se la tua applicazione richiede la possibilità di gestire la pianificazione dei processi, eseguire
i download in background o riprovare a stabilire il download dopo la perdita
della rete, valuta la possibilità di includere WorkManager e
ForegroundServices.
Il seguente codice di esempio per configurare un download utilizzando Cronet è tratto dal codelab di Cronet.
Kotlin
override suspend fun downloadImage(url: String): ImageDownloaderResult {
val startNanoTime = System.nanoTime()
return suspendCoroutine {
cont ->
val request = engine.newUrlRequestBuilder(url, object: ReadToMemoryCronetCallback() {
override fun onSucceeded(
request: UrlRequest,
info: UrlResponseInfo,
bodyBytes: ByteArray) {
cont.resume(ImageDownloaderResult(
successful = true,
blob = bodyBytes,
latency = Duration.ofNanos(System.nanoTime() - startNanoTime),
wasCached = info.wasCached(),
downloaderRef = this@CronetImageDownloader))
}
override fun onFailed(
request: UrlRequest,
info: UrlResponseInfo,
error: CronetException
) {
Log.w(LOGGER_TAG, "Cronet download failed!", error)
cont.resume(ImageDownloaderResult(
successful = false,
blob = ByteArray(0),
latency = Duration.ZERO,
wasCached = info.wasCached(),
downloaderRef = this@CronetImageDownloader))
}
}, executor)
request.build().start()
}
}
Java
@Override
public CompletableFuture<ImageDownloaderResult> downloadImage(String url) {
long startNanoTime = System.nanoTime();
return CompletableFuture.supplyAsync(() -> {
UrlRequest.Builder requestBuilder = engine.newUrlRequestBuilder(url, new ReadToMemoryCronetCallback() {
@Override
public void onSucceeded(UrlRequest request, UrlResponseInfo info, byte[] bodyBytes) {
return ImageDownloaderResult.builder()
.successful(true)
.blob(bodyBytes)
.latency(Duration.ofNanos(System.nanoTime() - startNanoTime))
.wasCached(info.wasCached())
.downloaderRef(CronetImageDownloader.this)
.build();
}
@Override
public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) {
Log.w(LOGGER_TAG, "Cronet download failed!", error);
return ImageDownloaderResult.builder()
.successful(false)
.blob(new byte[0])
.latency(Duration.ZERO)
.wasCached(info.wasCached())
.downloaderRef(CronetImageDownloader.this)
.build();
}
}, executor);
UrlRequest urlRequest = requestBuilder.build();
urlRequest.start();
return urlRequest.getResult();
});
}
Risorse
- Pagina principale della documentazione di DownloadManager
- Report sulle vulnerabilità CVE di DownloadManager
- CVE 2018-9468 per l'aggiramento delle autorizzazioni Android
- SQL injection del provider di download di Android CVE-2018-9493
- CVE2018-9468: bypass dell'autorizzazione del fornitore di download di Android
- Pagina principale della documentazione di Cronet
- Istruzioni per l'utilizzo di Cronet in un'applicazione
- Implementazione di esempio di Cronet
- Documentazione per Uri
- Documentazione per ForegroundService
- Documentazione di WorkManager