Categoria OWASP: MASVS-STORAGE: spazio di archiviazione
Panoramica
Le app che hanno come target Android 10 (API 29) o versioni precedenti non hanno ambito applicato
spazio di archiviazione. Ciò significa che qualsiasi dato archiviato nello spazio di archiviazione esterno può essere acceduto da qualsiasi altra applicazione con l'autorizzazione READ_EXTERNAL_STORAGE
.
Impatto
Nelle applicazioni che hanno come target Android 10 (API 29) o versioni precedenti, se i dati sensibili sono nella memoria esterna, qualsiasi applicazione sul dispositivo con L'autorizzazione READ_EXTERNAL_STORAGE può accedervi. Ciò consente di accedere ai file sensibili in modo invisibile all'utente in modo permanente o temporaneo nella memoria esterna. Inoltre, poiché i contenuti all'esterno spazio di archiviazione accessibile da qualsiasi applicazione sul sistema, applicazione dannosa che dichiara inoltre che l'autorizzazione WRITE_EXTERNAL_STORAGE può manomettere i file archiviati sulla memoria esterna, ad esempio per includere dati dannosi. Questo malware di dati, se caricati nell'applicazione, potrebbero essere progettati per ingannare gli utenti o ottenere l'esecuzione del codice.
Mitigazioni
Archiviazione con ambito (Android 10 e versioni successive)
Android 10
Per le applicazioni destinate ad Android 10, gli sviluppatori possono attivare esplicitamente la
archiviazione con ambito. A questo scopo, imposta
requestLegacyExternalStorage
viene impostato su false nella
AndroidManifest.xml
. Con lo spazio di archiviazione limitato, le applicazioni possono accedere solo ai file che hanno creato autonomamente sullo spazio di archiviazione esterno o ai tipi di file memorizzati utilizzando l'API MediaStore, ad esempio audio e video. Ciò contribuisce a proteggere la privacy e la sicurezza degli utenti.
Android 11 e versioni successive
Per le applicazioni che hanno come target Android 11 o versioni successive, il sistema operativo applica in modo forzato le
l'utilizzo dell'archiviazione con ambito, ovvero ignora
requestLegacyExternalStorage
e protegge automaticamente
delle applicazioni da accessi indesiderati.
Usa archiviazione interna per dati sensibili
Indipendentemente dalla versione di Android scelta come target, i dati sensibili di un'applicazione devono essere sempre archiviati nella memoria interna. L'accesso alla memoria interna è limitati automaticamente all'applicazione proprietaria grazie alla limitazione tramite sandbox di Android, pertanto può essere considerato sicuro, a meno che non sia rooted.
Cripta i dati sensibili
Se i casi d'uso dell'applicazione richiedono l'archiviazione di dati sensibili sul server archiviazione, i dati devono essere crittografati. Un algoritmo crittografico efficace è utilizzando il KeyStore Android per archiviare la chiave in modo sicuro.
In generale, la crittografia di tutti i dati sensibili è una pratica di sicurezza consigliata, no indipendentemente da dove sono archiviati.
È importante notare che la crittografia completa del disco (o la crittografia basata su file Android 10) è una misura volta a proteggere i dati dall'accesso fisico e da altre vettori d'attacco. Per questo motivo, per garantire la stessa misura di sicurezza, i dati sensibili memorizzati in uno spazio di archiviazione esterno devono essere inoltre criptati dall'applicazione.
Esegui controlli di integrità
Nei casi in cui i dati o il codice deve essere caricato dalla memoria esterna applicazioni, controlli di integrità per verificare che nessun'altra applicazione sia stata manomessa con questi dati o codici. Gli hash dei file devono essere archiviati in modo sicuro, preferibilmente criptati e nella memoria interna.
Kotlin
package com.example.myapplication
import java.io.BufferedInputStream
import java.io.FileInputStream
import java.io.IOException
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
object FileIntegrityChecker {
@Throws(IOException::class, NoSuchAlgorithmException::class)
fun getIntegrityHash(filePath: String?): String {
val md = MessageDigest.getInstance("SHA-256") // You can choose other algorithms as needed
val buffer = ByteArray(8192)
var bytesRead: Int
BufferedInputStream(FileInputStream(filePath)).use { fis ->
while (fis.read(buffer).also { bytesRead = it } != -1) {
md.update(buffer, 0, bytesRead)
}
}
private fun bytesToHex(bytes: ByteArray): String {
val sb = StringBuilder()
for (b in bytes) {
sb.append(String.format("%02x", b))
}
return sb.toString()
}
@Throws(IOException::class, NoSuchAlgorithmException::class)
fun verifyIntegrity(filePath: String?, expectedHash: String): Boolean {
val actualHash = getIntegrityHash(filePath)
return actualHash == expectedHash
}
@Throws(Exception::class)
@JvmStatic
fun main(args: Array<String>) {
val filePath = "/path/to/your/file"
val expectedHash = "your_expected_hash_value"
if (verifyIntegrity(filePath, expectedHash)) {
println("File integrity is valid!")
} else {
println("File integrity is compromised!")
}
}
}
Java
package com.example.myapplication;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class FileIntegrityChecker {
public static String getIntegrityHash(String filePath) throws IOException, NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256"); // You can choose other algorithms as needed
byte[] buffer = new byte[8192];
int bytesRead;
try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream(filePath))) {
while ((bytesRead = fis.read(buffer)) != -1) {
md.update(buffer, 0, bytesRead);
}
}
byte[] digest = md.digest();
return bytesToHex(digest);
}
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
public static boolean verifyIntegrity(String filePath, String expectedHash) throws IOException, NoSuchAlgorithmException {
String actualHash = getIntegrityHash(filePath);
return actualHash.equals(expectedHash);
}
public static void main(String[] args) throws Exception {
String filePath = "/path/to/your/file";
String expectedHash = "your_expected_hash_value";
if (verifyIntegrity(filePath, expectedHash)) {
System.out.println("File integrity is valid!");
} else {
System.out.println("File integrity is compromised!");
}
}
}
Risorse
- Spazio di archiviazione basato sugli ambiti
- READ_EXTERNAL_STORAGE
- WRITE_EXTERNAL_STORAGE
- requestLegacyExternalStorage
- Panoramica dell'archiviazione di file e dati
- Archiviazione dei dati (specifica per app)
- Crittografia
- Keystore
- Crittografia basata su file
- Crittografia completa del disco