اعتماد نامناسب به نام فایل ارائه شده توسط ContentProvider
با مجموعهها، منظم بمانید
ذخیره و طبقهبندی محتوا براساس اولویتهای شما.
دسته OWASP: MASVS-CODE: کیفیت کد
نمای کلی
FileProvider ، زیر کلاس ContentProvider ، در نظر گرفته شده است تا روشی امن برای یک برنامه کاربردی ("برنامه سرور") برای اشتراک گذاری فایل ها با برنامه دیگر ("برنامه مشتری") ارائه دهد. با این حال، اگر برنامه سرویس گیرنده به درستی نام فایل ارائه شده توسط برنامه سرور را مدیریت نکند، یک برنامه سرور تحت کنترل مهاجم ممکن است بتواند FileProvider مخرب خود را برای بازنویسی فایلها در حافظه برنامه ویژه برنامه کلاینت پیادهسازی کند.
تاثیر
اگر مهاجم بتواند فایلهای یک برنامه را بازنویسی کند، این میتواند منجر به اجرای کد مخرب شود (با بازنویسی کد برنامه)، یا اجازه دهد رفتار برنامه را تغییر دهد (مثلاً با بازنویسی تنظیمات برگزیده مشترک برنامه یا سایر فایلهای پیکربندی).
اقدامات کاهشی
هنگام استفاده از تماس های سیستم فایل، با ایجاد یک نام فایل منحصر به فرد هنگام نوشتن فایل دریافتی در حافظه، ترجیح دهید بدون ورودی کاربر کار کنید.
به عبارت دیگر: وقتی برنامه مشتری فایل دریافتی را در فضای ذخیره سازی می نویسد، باید نام فایل ارائه شده توسط برنامه سرور را نادیده بگیرد و در عوض از شناسه منحصر به فرد تولید شده داخلی خود به عنوان نام فایل استفاده کند.
این مثال بر اساس کد موجود در https://developer.android.com/training/secure-file-sharing/request-file است:
کاتلین
// Code in
// https://developer.android.com/training/secure-file-sharing/request-file#OpenFile
// used to obtain file descriptor (fd)
try {
val inputStream = FileInputStream(fd)
val tempFile = File.createTempFile("temp", null, cacheDir)
val outputStream = FileOutputStream(tempFile)
val buf = ByteArray(1024)
var len: Int
len = inputStream.read(buf)
while (len > 0) {
if (len != -1) {
outputStream.write(buf, 0, len)
len = inputStream.read(buf)
}
}
inputStream.close()
outputStream.close()
} catch (e: IOException) {
e.printStackTrace()
Log.e("MainActivity", "File copy error.")
return
}
جاوا
// Code in
// https://developer.android.com/training/secure-file-sharing/request-file#OpenFile
// used to obtain file descriptor (fd)
FileInputStream inputStream = new FileInputStream(fd);
// Create a temporary file
File tempFile = File.createTempFile("temp", null, getCacheDir());
// Copy the contents of the file to the temporary file
try {
OutputStream outputStream = new FileOutputStream(tempFile))
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
} catch (IOException e) {
e.printStackTrace();
Log.e("MainActivity", "File copy error.");
return;
}
نام فایل های ارائه شده را پاکسازی کنید
هنگام نوشتن فایل دریافتی در ذخیره سازی، نام فایل ارائه شده را پاکسازی کنید.
این کاهش نسبت به کاهش قبلی مطلوبیت کمتری دارد زیرا رسیدگی به تمام موارد بالقوه می تواند چالش برانگیز باشد. با این وجود: اگر ایجاد یک نام فایل منحصر به فرد عملی نیست، برنامه مشتری باید نام فایل ارائه شده را پاکسازی کند. پاکسازی شامل:
- پاکسازی کاراکترهای پیمایش مسیر در نام فایل
- انجام یک متعارف برای تأیید اینکه هیچ پیمایش مسیری وجود ندارد
این کد مثال بر اساس راهنمایی در مورد بازیابی اطلاعات فایل است:
کاتلین
protected fun sanitizeFilename(displayName: String): String {
val badCharacters = arrayOf("..", "/")
val segments = displayName.split("/")
var fileName = segments[segments.size - 1]
for (suspString in badCharacters) {
fileName = fileName.replace(suspString, "_")
}
return fileName
}
val displayName = returnCursor.getString(nameIndex)
val fileName = sanitizeFilename(displayName)
val filePath = File(context.filesDir, fileName).path
// saferOpenFile defined in Android developer documentation
val outputFile = saferOpenFile(filePath, context.filesDir.canonicalPath)
// fd obtained using Requesting a shared file from Android developer
// documentation
val inputStream = FileInputStream(fd)
// Copy the contents of the file to the new file
try {
val outputStream = FileOutputStream(outputFile)
val buffer = ByteArray(1024)
var length: Int
while (inputStream.read(buffer).also { length = it } > 0) {
outputStream.write(buffer, 0, length)
}
} catch (e: IOException) {
// Handle exception
}
جاوا
protected String sanitizeFilename(String displayName) {
String[] badCharacters = new String[] { "..", "/" };
String[] segments = displayName.split("/");
String fileName = segments[segments.length - 1];
for (String suspString : badCharacters) {
fileName = fileName.replace(suspString, "_");
}
return fileName;
}
String displayName = returnCursor.getString(nameIndex);
String fileName = sanitizeFilename(displayName);
String filePath = new File(context.getFilesDir(), fileName).getPath();
// saferOpenFile defined in Android developer documentation
File outputFile = saferOpenFile(filePath,
context.getFilesDir().getCanonicalPath());
// fd obtained using Requesting a shared file from Android developer
// documentation
FileInputStream inputStream = new FileInputStream(fd);
// Copy the contents of the file to the new file
try {
OutputStream outputStream = new FileOutputStream(outputFile))
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, length);
}
} catch (IOException e) {
// Handle exception
}
مشارکت کنندگان: دیمیتریوس والساماراس و مایکل پک از Microsoft Threat Intelligence
منابع
محتوا و نمونه کدها در این صفحه مشمول پروانههای توصیفشده در پروانه محتوا هستند. جاوا و OpenJDK علامتهای تجاری یا علامتهای تجاری ثبتشده Oracle و/یا وابستههای آن هستند.
تاریخ آخرین بهروزرسانی 2025-07-29 بهوقت ساعت هماهنگ جهانی.
[null,null,["تاریخ آخرین بهروزرسانی 2025-07-29 بهوقت ساعت هماهنگ جهانی."],[],[],null,["# Improperly trusting ContentProvider-provided filename\n\n\u003cbr /\u003e\n\n**OWASP category:** [MASVS-CODE: Code Quality](https://mas.owasp.org/MASVS/10-MASVS-CODE)\n\n\nOverview\n--------\n\n[*FileProvider*](/reference/androidx/core/content/FileProvider), a subclass of [*ContentProvider*](/reference/android/content/ContentProvider), is intended to\nprovide a secure method for an application (\"server application\") to [share\nfiles with another application](/training/secure-file-sharing) (\"client application\"). However, if the\nclient application does not properly handle the filename provided by the server\napplication, an attacker-controlled server application may be able to implement\nits own malicious *FileProvider* to overwrite files in the client application's\napp-specific storage.\n\nImpact\n------\n\nIf an attacker can overwrite an application's files, this can lead to malicious\ncode execution (by overwriting the application's code), or allow otherwise\nmodifying the application's behavior (for example, by overwriting the\napplication's shared preferences or other configuration files).\n\nMitigations\n-----------\n\n### Don't Trust User Input\n\nPrefer working without user input when using file system calls by generating a\nunique filename when writing the received file to storage.\n\nIn other words: When the client application writes the received file to storage,\nit should ignore the filename provided by the server application and instead use\nits own internally generated unique identifier as the filename.\n\nThis example builds upon the code found at\n[https://developer.android.com/training/secure-file-sharing/request-file](/training/secure-file-sharing/request-file#java): \n\n### Kotlin\n\n // Code in\n // https://developer.android.com/training/secure-file-sharing/request-file#OpenFile\n // used to obtain file descriptor (fd)\n\n try {\n val inputStream = FileInputStream(fd)\n val tempFile = File.createTempFile(\"temp\", null, cacheDir)\n val outputStream = FileOutputStream(tempFile)\n val buf = ByteArray(1024)\n var len: Int\n len = inputStream.read(buf)\n while (len \u003e 0) {\n if (len != -1) {\n outputStream.write(buf, 0, len)\n len = inputStream.read(buf)\n }\n }\n inputStream.close()\n outputStream.close()\n } catch (e: IOException) {\n e.printStackTrace()\n Log.e(\"MainActivity\", \"File copy error.\")\n return\n }\n\n### Java\n\n // Code in\n // https://developer.android.com/training/secure-file-sharing/request-file#OpenFile\n // used to obtain file descriptor (fd)\n\n FileInputStream inputStream = new FileInputStream(fd);\n\n // Create a temporary file\n File tempFile = File.createTempFile(\"temp\", null, getCacheDir());\n\n // Copy the contents of the file to the temporary file\n try {\n OutputStream outputStream = new FileOutputStream(tempFile))\n byte[] buffer = new byte[1024];\n int length;\n while ((length = inputStream.read(buffer)) \u003e 0) {\n outputStream.write(buffer, 0, length);\n }\n } catch (IOException e) {\n e.printStackTrace();\n Log.e(\"MainActivity\", \"File copy error.\");\n return;\n }\n\n### Sanitize Provided Filenames\n\nSanitize the provided filename when writing the received file to storage.\n\nThis mitigation is less desirable than the preceding mitigation because it can\nbe challenging to handle all potential cases. Nonetheless: If generating a\nunique filename is not practical, the client application should sanitize the\nprovided filename. Sanitization includes:\n\n- Sanitizing path traversal characters in the filename\n- Performing a canonicalization to confirm there are no path traversals\n\nThis example code builds upon the guidance on [retrieving file information](/training/secure-file-sharing/retrieve-info): \n\n### Kotlin\n\n protected fun sanitizeFilename(displayName: String): String {\n val badCharacters = arrayOf(\"..\", \"/\")\n val segments = displayName.split(\"/\")\n var fileName = segments[segments.size - 1]\n for (suspString in badCharacters) {\n fileName = fileName.replace(suspString, \"_\")\n }\n return fileName\n }\n\n val displayName = returnCursor.getString(nameIndex)\n val fileName = sanitizeFilename(displayName)\n val filePath = File(context.filesDir, fileName).path\n\n // saferOpenFile defined in Android developer documentation\n val outputFile = saferOpenFile(filePath, context.filesDir.canonicalPath)\n\n // fd obtained using Requesting a shared file from Android developer\n // documentation\n\n val inputStream = FileInputStream(fd)\n\n // Copy the contents of the file to the new file\n try {\n val outputStream = FileOutputStream(outputFile)\n val buffer = ByteArray(1024)\n var length: Int\n while (inputStream.read(buffer).also { length = it } \u003e 0) {\n outputStream.write(buffer, 0, length)\n }\n } catch (e: IOException) {\n // Handle exception\n }\n\n### Java\n\n protected String sanitizeFilename(String displayName) {\n String[] badCharacters = new String[] { \"..\", \"/\" };\n String[] segments = displayName.split(\"/\");\n String fileName = segments[segments.length - 1];\n for (String suspString : badCharacters) {\n fileName = fileName.replace(suspString, \"_\");\n }\n return fileName;\n }\n\n String displayName = returnCursor.getString(nameIndex);\n String fileName = sanitizeFilename(displayName);\n String filePath = new File(context.getFilesDir(), fileName).getPath();\n\n // saferOpenFile defined in Android developer documentation\n\n File outputFile = saferOpenFile(filePath,\n context.getFilesDir().getCanonicalPath());\n\n // fd obtained using Requesting a shared file from Android developer\n // documentation\n\n FileInputStream inputStream = new FileInputStream(fd);\n\n // Copy the contents of the file to the new file\n try {\n OutputStream outputStream = new FileOutputStream(outputFile))\n byte[] buffer = new byte[1024];\n int length;\n while ((length = inputStream.read(buffer)) \u003e 0) {\n outputStream.write(buffer, 0, length);\n }\n } catch (IOException e) {\n // Handle exception\n }\n\nContributors: Dimitrios Valsamaras and Michael Peck of Microsoft Threat\nIntelligence\n\nResources\n---------\n\n- [Dirty Stream Attack: Turning Android Share Targets Into Attack Vectors](https://i.blackhat.com/Asia-23/AS-23-Valsamaras-Dirty-Stream-Attack-Turning-Android.pdf)\n- [Secure File Sharing](/training/secure-file-sharing)\n- [Request a Shared File documentation](/training/secure-file-sharing/request-file)\n- [Retrieve Info](/training/secure-file-sharing/retrieve-info)\n- [FileProvider](/reference/androidx/core/content/FileProvider)\n- [Path Traversal](/topic/security/risks/path-traversal)\n- [CWE-73 External Control of Filename or Path](https://cwe.mitre.org/data/definitions/73)"]]