Unsicherer Download-Manager
Mit Sammlungen den Überblick behalten
Sie können Inhalte basierend auf Ihren Einstellungen speichern und kategorisieren.
OWASP-Kategorie: MASVS-NETWORK: Netzwerkkommunikation
Übersicht
DownloadManager ist ein Systemdienst, der in API-Ebene 9 eingeführt wurde. Sie verarbeitet langlaufende HTTP-Downloads und ermöglicht es Anwendungen, Dateien als Hintergrundaufgabe herunterzuladen. Die API verarbeitet HTTP-Interaktionen und versucht, Downloads nach Fehlern oder bei Verbindungsänderungen und Systemneustarts noch einmal auszuführen.
Der DownloadManager weist sicherheitsrelevante Schwächen auf, die ihn zu einer unsicheren Option für die Verwaltung von Downloads in Android-Anwendungen machen.
(1) CVEs beim Downloadanbieter
2018 wurden beim Download Provider drei CVEs gefunden und gepatcht. Im Folgenden finden Sie eine Zusammenfassung (siehe technische Details).
- Umgehung der Berechtigungen des Downloadanbieters: Ohne erteilte Berechtigungen könnte eine schädliche App alle Einträge vom Downloadanbieter abrufen, die potenziell vertrauliche Informationen wie Dateinamen, Beschreibungen, Titel, Pfade, URLs sowie vollständige Lese-/Schreibberechtigungen für alle heruntergeladenen Dateien enthalten können. Eine schädliche App könnte im Hintergrund ausgeführt werden, alle Downloads überwachen und ihren Inhalt aus der Ferne weitergeben oder die Dateien direkt ändern, bevor der rechtmäßige Antragsteller darauf zugreift. Dies kann zu einem Dienstausfall für Nutzer bei Kernanwendungen führen, einschließlich der Unfähigkeit, Updates herunterzuladen.
- SQL-Injection des Downloadanbieters: Über eine SQL-Injection-Sicherheitslücke kann eine schädliche Anwendung ohne Berechtigungen alle Einträge vom Downloadanbieter abrufen. Außerdem könnten Anwendungen mit eingeschränkten Berechtigungen wie
android.permission.INTERNET
über einen anderen URI auf den gesamten Datenbankinhalt zugreifen. Potenziell vertrauliche Informationen wie Dateinamen, Beschreibungen, Titel, Pfade und URLs können abgerufen werden. Je nach Berechtigungen ist möglicherweise auch der Zugriff auf heruntergeladene Inhalte möglich.
- Offenlegung von Informationen in Anfrageheadern von Downloadanbietern: Eine schädliche Anwendung mit der Berechtigung
android.permission.INTERNET
kann alle Einträge aus der Tabelle „Anfrageheader von Downloadanbietern“ abrufen. Diese Header können vertrauliche Informationen wie Sitzungscookies oder Authentifizierungsheader für Downloads enthalten, die unter anderem über den Android-Browser oder Google Chrome gestartet wurden. So kann ein Angreifer den Nutzer auf jeder Plattform, von der vertrauliche Nutzerdaten abgerufen wurden, imitieren.
(2) Gefährliche Berechtigungen
Der DownloadManager erfordert bei API-Levels unter 29 gefährliche Berechtigungen –
android.permission.WRITE_EXTERNAL_STORAGE
. Ab API-Ebene 29 sind keine android.permission.WRITE_EXTERNAL_STORAGE
-Berechtigungen erforderlich. Der URI muss aber auf einen Pfad in den Verzeichnissen der Anwendung oder auf einen Pfad im obersten Verzeichnis „Downloads“ verweisen.
(3) Abhängigkeit von Uri.parse()
DownloadManager verwendet die Methode Uri.parse()
, um den Speicherort des angeforderten Downloads zu parsen. Im Interesse der Leistung wendet die Klasse Uri
wenig bis gar keine Validierung nicht vertrauenswürdiger Eingaben an.
Positiv beeinflussen
Die Verwendung von DownloadManager kann zu Sicherheitslücken führen, wenn die WRITE-Berechtigungen für den externen Speicher ausgenutzt werden. Da die Berechtigung „android.permission.WRITE_EXTERNAL_STORAGE“ einen umfassenden Zugriff auf den externen Speicher ermöglicht, können Angreifer Dateien und Downloads unbemerkt ändern, potenziell schädliche Apps installieren, den Dienst für Haupt-Apps verweigern oder Apps zum Absturz bringen. Böswillige Akteure könnten auch manipulieren, was an Uri.parse() gesendet wird, um den Nutzer dazu zu bringen, eine schädliche Datei herunterzuladen.
Abwehrmaßnahmen
Anstatt DownloadManager zu verwenden, richten Sie Downloads direkt in Ihrer Anwendung mit einem HTTP-Client (z. B. Cronet), einem Prozessplaner/-manager und einer Möglichkeit ein, die Wiederholungsversuche bei Netzwerkausfall zu gewährleisten. Die Dokumentation der Bibliothek enthält einen Link zu einer Beispiel-App sowie eine Anleitung zur Implementierung.
Wenn für Ihre Anwendung die Möglichkeit erforderlich ist, die Prozessplanung zu verwalten, Downloads im Hintergrund auszuführen oder nach einem Netzwerkverlust einen erneuten Verbindungsversuch zu starten, sollten Sie WorkManager
und ForegroundServices
einschließen.
Den folgenden Beispielcode zum Einrichten eines Downloads mit Cronet finden Sie aus dem Cronet-Codelab.
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();
});
}
Ressourcen
Alle Inhalte und Codebeispiele auf dieser Seite unterliegen den Lizenzen wie im Abschnitt Inhaltslizenz beschrieben. Java und OpenJDK sind Marken oder eingetragene Marken von Oracle und/oder seinen Tochtergesellschaften.
Zuletzt aktualisiert: 2025-07-26 (UTC).
[[["Leicht verständlich","easyToUnderstand","thumb-up"],["Mein Problem wurde gelöst","solvedMyProblem","thumb-up"],["Sonstiges","otherUp","thumb-up"]],[["Benötigte Informationen nicht gefunden","missingTheInformationINeed","thumb-down"],["Zu umständlich/zu viele Schritte","tooComplicatedTooManySteps","thumb-down"],["Nicht mehr aktuell","outOfDate","thumb-down"],["Problem mit der Übersetzung","translationIssue","thumb-down"],["Problem mit Beispielen/Code","samplesCodeIssue","thumb-down"],["Sonstiges","otherDown","thumb-down"]],["Zuletzt aktualisiert: 2025-07-26 (UTC)."],[],[],null,["# Unsafe Download Manager\n\n\u003cbr /\u003e\n\n**OWASP category:** [MASVS-NETWORK: Network Communication](https://mas.owasp.org/MASVS/08-MASVS-NETWORK)\n\nOverview\n--------\n\nDownloadManager is a system service introduced in API level 9. It handles\nlong-running HTTP downloads and allows applications to download files as a\nbackground task. Its API handles HTTP interactions and retries downloads after\nfailures or across connectivity changes and system reboots.\n\nDownloadManager has security relevant weaknesses that make it an insecure choice\nfor managing downloads in Android applications.\n\n**(1) CVEs in Download Provider**\n\nIn 2018, three [CVEs](https://ioactive.com/multiple-vulnerabilities-in-androids-download-provider-cve-2018-9468-cve-2018-9493-cve-2018-9546/) were found and patched in Download\nProvider. A summary of each follows (see [technical details](https://ioactive.com/multiple-vulnerabilities-in-androids-download-provider-cve-2018-9468-cve-2018-9493-cve-2018-9546/)).\n\n- **Download Provider Permission Bypass** -- With no granted permissions, a malicious app could retrieve all entries from the Download Provider, which could include potentially sensitive information such as file names, descriptions, titles, paths, URLs, as well as full READ/WRITE permissions to all downloaded files. A malicious app could run in the background, monitoring all downloads and leaking their contents remotely, or modifying the files on-the-fly before they are accessed by the legitimate requester. This could cause a denial-of-service for the user for core applications, including the inability to download updates.\n- **Download Provider SQL Injection** -- Through a SQL injection vulnerability, a malicious application with no permissions could retrieve all entries from the Download Provider. Also, applications with limited permissions, such as [`android.permission.INTERNET`](http://go/android-dev/reference/android/Manifest.permission#INTERNET), could also access all database contents from a different URI. Potentially sensitive information such as file names, descriptions, titles, paths, URLs could be retrieved, and, depending on permissions, access to downloaded contents may be possible as well.\n- **Download Provider Request Headers Information Disclosure** -- A malicious application with the [`android.permission.INTERNET`](http://go/android-dev/reference/android/Manifest.permission#INTERNET) permission granted could retrieve all entries from the Download Provider request headers table. These headers may include sensitive information, such as session cookies or authentication headers, for any download started from the Android Browser or Google Chrome, among other applications. This could allow an attacker to impersonate the user on any platform from which sensitive user data was obtained.\n\n**(2) Dangerous Permissions**\n\nDownloadManager in API levels lower than 29 requires dangerous permissions --\n[`android.permission.WRITE_EXTERNAL_STORAGE`](http://go/android-dev/reference/android/Manifest.permission#WRITE_EXTERNAL_STORAGE). For API level 29\nand higher, [`android.permission.WRITE_EXTERNAL_STORAGE`](http://go/android-dev/reference/android/Manifest.permission#WRITE_EXTERNAL_STORAGE)\npermissions are not required, but the URI must refer to a path within the\ndirectories owned by the application or a path within the top-level \"Downloads\"\ndirectory.\n\n**(3) Reliance on** `Uri.parse()`\n\nDownloadManager relies on the `Uri.parse()` method to parse the location of the\nrequested download. In the interest of performance, the `Uri` class applies\nlittle to no validation on untrusted input.\n\nImpact\n------\n\nUsing DownloadManager may lead to vulnerabilities through the exploitation of\nWRITE permissions to external storage. Since\nandroid.permission.WRITE_EXTERNAL_STORAGE permissions allow broad access to\nexternal storage, it is possible for an attacker to silently modify files and\ndownloads, install potentially malicious apps, deny service to core apps, or\ncause apps to crash. Malicious actors could also manipulate what is sent to\nUri.parse() to cause the user to download a harmful file.\n\nMitigations\n-----------\n\nInstead of using DownloadManager, set up downloads directly in your app using an\nHTTP client (such as Cronet), a process scheduler/manager, and a way to ensure\nretries if there is network loss. The [documentation of the library](/develop/connectivity/cronet) includes\na link to a [sample](https://github.com/GoogleChromeLabs/cronet-sample) app as well as [instructions](/develop/connectivity/cronet/start) on how\nto implement it.\n\nIf your application requires the ability to manage process scheduling, run\ndownloads in the background, or retry establishing the download after network\nloss, then consider including [`WorkManager`](/reference/androidx/work/WorkManager) and\n[`ForegroundServices`](/develop/background-work/services/foreground-services).\n\nExample code for setting up a download using Cronet is as follows, taken from\nthe Cronet [codelab](/codelabs/cronet#8). \n\n### Kotlin\n\n override suspend fun downloadImage(url: String): ImageDownloaderResult {\n val startNanoTime = System.nanoTime()\n return suspendCoroutine {\n cont -\u003e\n val request = engine.newUrlRequestBuilder(url, object: ReadToMemoryCronetCallback() {\n override fun onSucceeded(\n request: UrlRequest,\n info: UrlResponseInfo,\n bodyBytes: ByteArray) {\n cont.resume(ImageDownloaderResult(\n successful = true,\n blob = bodyBytes,\n latency = Duration.ofNanos(System.nanoTime() - startNanoTime),\n wasCached = info.wasCached(),\n downloaderRef = this@CronetImageDownloader))\n }\n override fun onFailed(\n request: UrlRequest,\n info: UrlResponseInfo,\n error: CronetException\n ) {\n Log.w(LOGGER_TAG, \"Cronet download failed!\", error)\n cont.resume(ImageDownloaderResult(\n successful = false,\n blob = ByteArray(0),\n latency = Duration.ZERO,\n wasCached = info.wasCached(),\n downloaderRef = this@CronetImageDownloader))\n }\n }, executor)\n request.build().start()\n }\n }\n\n### Java\n\n @Override\n public CompletableFuture\u003cImageDownloaderResult\u003e downloadImage(String url) {\n long startNanoTime = System.nanoTime();\n return CompletableFuture.supplyAsync(() -\u003e {\n UrlRequest.Builder requestBuilder = engine.newUrlRequestBuilder(url, new ReadToMemoryCronetCallback() {\n @Override\n public void onSucceeded(UrlRequest request, UrlResponseInfo info, byte[] bodyBytes) {\n return ImageDownloaderResult.builder()\n .successful(true)\n .blob(bodyBytes)\n .latency(Duration.ofNanos(System.nanoTime() - startNanoTime))\n .wasCached(info.wasCached())\n .downloaderRef(CronetImageDownloader.this)\n .build();\n }\n @Override\n public void onFailed(UrlRequest request, UrlResponseInfo info, CronetException error) {\n Log.w(LOGGER_TAG, \"Cronet download failed!\", error);\n return ImageDownloaderResult.builder()\n .successful(false)\n .blob(new byte[0])\n .latency(Duration.ZERO)\n .wasCached(info.wasCached())\n .downloaderRef(CronetImageDownloader.this)\n .build();\n }\n }, executor);\n UrlRequest urlRequest = requestBuilder.build();\n urlRequest.start();\n return urlRequest.getResult();\n });\n }\n\nResources\n---------\n\n- [Main documentation page for DownloadManager](/reference/android/app/DownloadManager)\n- [Report for DownloadManager CVEs](https://ioactive.com/multiple-vulnerabilities-in-androids-download-provider-cve-2018-9468-cve-2018-9493-cve-2018-9546/)\n- [Android Permission Bypass CVE 2018-9468](https://ioactive.com/wp-content/uploads/2019/04/IOActive-Security-Advisory-Androids-Download-Provider-Permission-Bypass-CVE-2018-9468.pdf)\n- [Android Download Provider SQL Injection CVE-2018- 9493](https://act-on.ioactive.com/acton/attachment/34793/f-722b41b4-7aff-4b35-9925-c221a217744d/1/-/-/-/-/cve-2018-9493.pdf)\n- [Android Download Provider Permission Bypass CVE2018-9468](https://act-on.ioactive.com/acton/attachment/34793/f-3b8bb46b-d105-4efd-97a1-9970bfa6928b/1/-/-/-/-/cve-2018-9546.pdf)\n- [Main documentation page for Cronet](/develop/connectivity/cronet)\n- [Instructions for using Cronet in an application](/develop/connectivity/cronet/start#java)\n- [Sample Cronet implementation](https://github.com/GoogleChromeLabs/cronet-sample)\n- [Documentation for Uri](/reference/android/net/Uri)\n- [Documentation for ForegroundService](/develop/background-work/services/foreground-services)\n- [Documentation for WorkManager](/reference/androidx/work/WorkManager)"]]