مدیر دانلود ناامن
با مجموعهها، منظم بمانید
ذخیره و طبقهبندی محتوا براساس اولویتهای شما.
دسته OWASP: MASVS-NETWORK: Network Communication
نمای کلی
DownloadManager یک سرویس سیستمی است که در سطح 9 API معرفی شده است. بارگیری های طولانی مدت HTTP را مدیریت می کند و به برنامه ها اجازه می دهد فایل ها را به عنوان یک کار پس زمینه بارگیری کنند. API آن تعاملات HTTP را مدیریت می کند و پس از خرابی یا در طول تغییرات اتصال و راه اندازی مجدد سیستم، بارگیری را دوباره امتحان می کند.
DownloadManager دارای نقاط ضعف مرتبط با امنیت است که آن را به انتخابی ناامن برای مدیریت دانلودها در برنامه های اندروید تبدیل می کند.
(1) CVE در ارائه دهنده دانلود
در سال 2018، سه CVE در ارائه دهنده دانلود پیدا و وصله شد. خلاصه ای از هر یک در ادامه می آید (به جزئیات فنی مراجعه کنید).
- دور زدن مجوز ارائهدهنده دانلود – بدون هیچ مجوزی، یک برنامه مخرب میتواند تمام ورودیهای ارائهدهنده دانلود را بازیابی کند، که میتواند شامل اطلاعات بالقوه حساس مانند نام فایلها، توضیحات، عنوانها، مسیرها، آدرسهای اینترنتی و همچنین مجوزهای کامل READ/WRITE باشد. تمام فایل های دانلود شده یک برنامه مخرب میتواند در پسزمینه اجرا شود، همه بارگیریها را زیر نظر بگیرد و محتویات آنها را از راه دور فاش کند، یا فایلها را در لحظه قبل از دسترسی درخواستکننده قانونی اصلاح کند. این می تواند باعث انکار سرویس برای کاربر برای برنامه های اصلی شود، از جمله ناتوانی در دانلود به روز رسانی.
- Download Provider SQL Injection – از طریق یک آسیبپذیری تزریق SQL، یک برنامه مخرب بدون مجوز میتواند همه ورودیها را از ارائهدهنده دانلود بازیابی کند. همچنین، برنامههایی با مجوزهای محدود، مانند
android.permission.INTERNET
، همچنین میتوانند از یک URI دیگر به تمام محتوای پایگاه داده دسترسی داشته باشند. اطلاعات بالقوه حساس مانند نام فایل ها، توضیحات، عنوان ها، مسیرها، URL ها می توانند بازیابی شوند و بسته به مجوزها، دسترسی به محتوای دانلود شده نیز ممکن است امکان پذیر باشد. - افشای اطلاعات سرصفحه درخواست ارائه دهنده دانلود - یک برنامه مخرب با مجوز
android.permission.INTERNET
اعطا شده می تواند همه ورودی ها را از جدول سرصفحه درخواست ارائه دهنده دانلود بازیابی کند. این سرصفحهها ممکن است شامل اطلاعات حساسی مانند کوکیهای جلسه یا سرصفحههای احراز هویت برای هر بارگیری شروع شده از مرورگر Android یا Google Chrome و سایر برنامهها باشد. این می تواند به مهاجم اجازه دهد تا در هر پلتفرمی که داده های حساس کاربر از آن به دست آمده است، هویت کاربر را جعل کند.
(2) مجوزهای خطرناک
DownloadManager در سطوح API کمتر از 29 به مجوزهای خطرناک نیاز دارد - android.permission.WRITE_EXTERNAL_STORAGE
. برای سطح API 29 و بالاتر، مجوزهای android.permission.WRITE_EXTERNAL_STORAGE
لازم نیست، اما URI باید به مسیری در فهرستهای متعلق به برنامه یا مسیری در فهرست «دانلودها» سطح بالا مراجعه کند.
(3) تکیه بر Uri.parse()
DownloadManager به متد Uri.parse()
برای تجزیه مکان دانلود درخواستی متکی است. به نفع عملکرد، کلاس Uri
اعتبار کمی برای ورودی نامعتبر اعمال می کند.
تاثیر
استفاده از DownloadManager ممکن است منجر به آسیبپذیریهایی از طریق بهرهبرداری از مجوزهای WRITE در حافظه خارجی شود. از آنجایی که مجوزهای android.permission.WRITE_EXTERNAL_STORAGE امکان دسترسی گسترده به فضای ذخیرهسازی خارجی را فراهم میکند، این امکان برای مهاجم وجود دارد که بیصدا فایلها و بارگیریها را تغییر دهد، برنامههای بالقوه مخرب را نصب کند، سرویسدهی به برنامههای اصلی را رد کند یا باعث خرابی برنامهها شود. عوامل مخرب همچنین می توانند آنچه را که به Uri.parse() ارسال می شود دستکاری کنند تا کاربر یک فایل مضر را دانلود کند.
اقدامات کاهشی
به جای استفاده از DownloadManager، دانلودها را مستقیماً در برنامه خود با استفاده از یک کلاینت HTTP (مانند Cronet)، یک برنامهریز/مدیر فرآیند، و راهی برای اطمینان از تلاشهای مجدد در صورت قطع شدن شبکه، تنظیم کنید. مستندات کتابخانه شامل پیوندی به یک برنامه نمونه و همچنین دستورالعملهایی در مورد نحوه اجرای آن است.
اگر برنامه شما به توانایی مدیریت زمانبندی فرآیند، اجرای بارگیریها در پسزمینه، یا ایجاد مجدد دانلود پس از از دست دادن شبکه نیاز دارد، سپس WorkManager
و ForegroundServices
را در نظر بگیرید.
کد مثال برای راه اندازی دانلود با استفاده از کرونت به شرح زیر است که از لبه کد Cronet گرفته شده است.
کاتلین
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()
}
}
جاوا
@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();
});
}
منابع
محتوا و نمونه کدها در این صفحه مشمول پروانههای توصیفشده در پروانه محتوا هستند. جاوا و OpenJDK علامتهای تجاری یا علامتهای تجاری ثبتشده Oracle و/یا وابستههای آن هستند.
تاریخ آخرین بهروزرسانی 2025-07-29 بهوقت ساعت هماهنگ جهانی.
[null,null,["تاریخ آخرین بهروزرسانی 2025-07-29 بهوقت ساعت هماهنگ جهانی."],[],[],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)"]]