Considera impropriamente attendibile il nome file fornito da ContentProvider
Mantieni tutto organizzato con le raccolte
Salva e classifica i contenuti in base alle tue preferenze.
Categoria OWASP: MASVS-CODE: Code Quality
Panoramica
FileProvider, una sottoclasse di ContentProvider, ha lo scopo di
fornire un metodo sicuro per un'applicazione ("applicazione server") per condividere
file con un'altra applicazione ("applicazione client"). Tuttavia, se l'applicazione client non gestisce correttamente il nome file fornito dall'applicazione server, un'applicazione server controllata da un malintenzionato potrebbe essere in grado di implementare il proprio FileProvider dannoso per sovrascrivere i file nello spazio di archiviazione specifico dell'app dell'applicazione client.
Impatto
Se un malintenzionato può sovrascrivere i file di un'applicazione, ciò può portare all'esecuzione di codice dannoso (sovrascrivendo il codice dell'applicazione) o consentire di modificare in altro modo il comportamento dell'applicazione (ad esempio, sovrascrivendo le preferenze condivise dell'applicazione o altri file di configurazione).
Mitigazioni
Preferisci lavorare senza input dell'utente quando utilizzi chiamate al file system generando un nome file univoco quando scrivi il file ricevuto nell'archiviazione.
In altre parole, quando l'applicazione client scrive il file ricevuto nell'archivio,
deve ignorare il nome file fornito dall'applicazione server e utilizzare
il proprio identificatore univoco generato internamente come nome file.
Questo esempio si basa sul codice disponibile all'indirizzo
https://developer.android.com/training/secure-file-sharing/request-file:
Kotlin
// 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
}
Java
// 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;
}
Eliminazione dei nomi file forniti
Sanitizza il nome file fornito durante la scrittura del file ricevuto nello spazio di archiviazione.
Questa mitigazione è meno auspicabile di quella precedente perché può
essere difficile gestire tutti i potenziali casi. Tuttavia, se la generazione di un nome file univoco non è pratica, l'applicazione client deve sanificare il nome file fornito. La sanificazione include:
- Pulizia dei caratteri di attraversamento del percorso nel nome file
- Eseguire una canonizzazione per verificare che non ci siano attraversamenti di percorsi
Questo codice di esempio si basa sulle indicazioni per recuperare le informazioni sui file:
Kotlin
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
}
Java
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
}
Collaboratori: Dimitrios Valsamaras e Michael Peck di Microsoft Threat
Intelligence
Risorse
I campioni di contenuti e codice in questa pagina sono soggetti alle licenze descritte nella Licenza per i contenuti. Java e OpenJDK sono marchi o marchi registrati di Oracle e/o delle sue società consociate.
Ultimo aggiornamento 2025-07-27 UTC.
[[["Facile da capire","easyToUnderstand","thumb-up"],["Il problema è stato risolto","solvedMyProblem","thumb-up"],["Altra","otherUp","thumb-up"]],[["Mancano le informazioni di cui ho bisogno","missingTheInformationINeed","thumb-down"],["Troppo complicato/troppi passaggi","tooComplicatedTooManySteps","thumb-down"],["Obsoleti","outOfDate","thumb-down"],["Problema di traduzione","translationIssue","thumb-down"],["Problema relativo a esempi/codice","samplesCodeIssue","thumb-down"],["Altra","otherDown","thumb-down"]],["Ultimo aggiornamento 2025-07-27 UTC."],[],[],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)"]]