Güvenli Olmayan İndirme Yöneticisi
Koleksiyonlar ile düzeninizi koruyun
İçeriği tercihlerinize göre kaydedin ve kategorilere ayırın.
OWASP kategorisi: MASVS-NETWORK: Ağ İletişimi
Genel Bakış
DownloadManager, API düzeyi 9'da kullanıma sunulan bir sistem hizmetidir. Uzun süren HTTP indirme işlemlerini yönetir ve uygulamaların arka plan görevi olarak dosya indirmesine olanak tanır. API'si, HTTP etkileşimlerini yönetir ve bağlantı değişiklikleri ile sistem yeniden başlatmaları sonrasında veya başarısız olduktan sonra indirmeleri yeniden dener.
DownloadManager, Android uygulamalarında indirmeleri yönetmek için güvenli olmayan bir seçim haline getiren güvenlikle ilgili zayıflıklara sahiptir.
(1) İndirme Sağlayıcısı'nda CVE'ler
2018'de İndirme Sağlayıcı'da üç CVE tespit edilerek düzeltildi. Bunların özetini aşağıda bulabilirsiniz (teknik ayrıntılara bakın).
- İndirme Sağlayıcı İzni Atlama: Kötü amaçlı bir uygulama, izin verilmeden İndirme Sağlayıcı'dan tüm girişleri alabilir. Bu girişler arasında dosya adları, açıklamalar, başlıklar, yollar, URL'ler gibi hassas olabilecek bilgiler ve indirilen tüm dosyalar için tam OKUMA/YAZMA izinleri bulunabilir. Kötü amaçlı bir uygulama arka planda çalışabilir, tüm indirilenleri izleyebilir ve içeriklerini uzaktan sızdırabilir veya meşru talep sahibi tarafından erişilmeden önce dosyaları anında değiştirebilir. Bu durum, kullanıcının temel uygulamalarda hizmet reddine (ör. güncellemeleri indirememesine) neden olabilir.
- İndirilen İçerik Sağlayıcısı SQL Yerleştirme: İzinleri olmayan kötü amaçlı bir uygulama, SQL yerleştirme güvenlik açığı aracılığıyla İndirilen İçerik Sağlayıcısı'ndaki tüm girişleri alabilir. Ayrıca,
android.permission.INTERNET
gibi sınırlı izinlere sahip uygulamalar da farklı bir URI'den tüm veritabanı içeriklerine erişebilir. Dosya adları, açıklamalar, başlıklar, yollar, URL'ler gibi hassas olabilecek bilgiler alınabilir ve izinlere bağlı olarak indirilen içeriklere de erişilebilir.
- İndirme Sağlayıcı İstek Başlıkları Bilgi Açıklaması:
android.permission.INTERNET
iznine sahip kötü amaçlı bir uygulama, İndirme Sağlayıcısı istek başlıkları tablosundaki tüm girişleri alabilir. Bu üstbilgiler, diğer uygulamalar arasında Android Tarayıcı veya Google Chrome'dan başlatılan tüm indirmeler için oturum çerezleri ya da kimlik doğrulama üstbilgileri gibi hassas bilgiler içerebilir. Bu, saldırganların hassas kullanıcı verilerinin elde edildiği herhangi bir platformda kullanıcının kimliğine bürünmesine olanak tanıyabilir.
(2) Tehlikeli İzinler
API düzeyi 29'dan düşük sürümlerde DownloadManager için tehlikeli izinler (android.permission.WRITE_EXTERNAL_STORAGE
) gerekir. API düzeyi 29 ve sonraki sürümler için android.permission.WRITE_EXTERNAL_STORAGE
izinleri gerekli değildir ancak URI, uygulamaya ait dizinlerdeki veya üst düzey "İndirilenler" dizinindeki bir yolu referans almalıdır.
(3) Uri.parse()
hizmetine güvenme
İndirme Yöneticisi, istenen indirme işleminin konumunu ayrıştırmak için Uri.parse()
yöntemini kullanır. Performans açısından Uri
sınıfı, güvenilmeyen girişlerde çok az veya hiç doğrulama uygulamaz.
Etki
DownloadManager'ın kullanılması, harici depolama cihazına WRITE izinlerinin kötüye kullanılmasıyla güvenlik açıklarına neden olabilir. android.permission.WRITE_EXTERNAL_STORAGE izinleri harici depolamaya geniş erişim izni verdiğinden, saldırganların dosyaları ve indirilenleri gizlice değiştirmesi, kötü amaçlı olabilecek uygulamalar yüklemesi, temel uygulamalara hizmet vermeyi reddetmesi veya uygulamaların kilitlenmesine neden olması mümkündür. Kötü amaçlı kullanıcılar, kullanıcının zararlı bir dosya indirmesine neden olmak için Uri.parse() işlevine gönderilen verileri de değiştirebilir.
Çözümler
DownloadManager yerine, bir HTTP istemcisi (Cronet gibi), bir işlem planlayıcı/yöneticisi ve ağ bağlantısı kesilirse yeniden denemelerin yapılmasını sağlayacak bir yöntem kullanarak indirmeleri doğrudan uygulamanızda ayarlayın. Kitaplığın dokümanları, örnek uygulamanın bağlantısını ve uygulamanın nasıl uygulanacağına dair talimatları içerir.
Uygulamanız; işlem planlamayı yönetme, indirme işlemlerini arka planda çalıştırma veya ağ kaybından sonra indirme işlemini yeniden yapmayı yeniden deneme özelliklerini gerektiriyorsa WorkManager
ve ForegroundServices
özelliklerini eklemeyi düşünebilirsiniz.
Cronet'i kullanarak indirme işlemi ayarlamak için örnek kod aşağıda verilmiştir. Bu kod, Cronet codelab'den alınmıştır.
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();
});
}
Kaynaklar
Bu sayfadaki içerik ve kod örnekleri, İçerik Lisansı sayfasında açıklanan lisanslara tabidir. Java ve OpenJDK, Oracle ve/veya satış ortaklarının tescilli ticari markasıdır.
Son güncelleme tarihi: 2025-07-26 UTC.
[[["Anlaması kolay","easyToUnderstand","thumb-up"],["Sorunumu çözdü","solvedMyProblem","thumb-up"],["Diğer","otherUp","thumb-up"]],[["İhtiyacım olan bilgiler yok","missingTheInformationINeed","thumb-down"],["Çok karmaşık / çok fazla adım var","tooComplicatedTooManySteps","thumb-down"],["Güncel değil","outOfDate","thumb-down"],["Çeviri sorunu","translationIssue","thumb-down"],["Örnek veya kod sorunu","samplesCodeIssue","thumb-down"],["Diğer","otherDown","thumb-down"]],["Son güncelleme tarihi: 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)"]]