Categoria OWASP: MASVS-STORAGE: Storage
Panoramica
La divulgazione di informazioni di log è un tipo di vulnerabilità in cui le app stampano dati sensibili nel log del dispositivo. Se esposte a utenti malintenzionati, queste informazioni sensibili possono essere preziose, ad esempio le credenziali o le informazioni che consentono l'identificazione personale (PII) di un utente, oppure possono consentire ulteriori attacchi.
Questo problema può verificarsi in uno dei seguenti scenari:
- Log generati dalle app:
- I log consentono intenzionalmente l'accesso ad attori non autorizzati, ma contengono accidentalmente dati sensibili.
- I log includono intenzionalmente dati sensibili, ma sono accessibili per errore ad attori non autorizzati.
- Log degli errori generici che a volte potrebbero stampare dati sensibili, a seconda del messaggio di errore attivato.
- Log generati esternamente:
- I componenti esterni sono responsabili della stampa dei log che includono dati sensibili.
Le istruzioni Android Log.* scrivono nel buffer di memoria comune logcat. A partire da Android 4.1 (livello API 16), solo le app di sistema privilegiate possono ottenere l'accesso in lettura a logcat dichiarando l'autorizzazione READ_LOGS. Tuttavia, Android supporta un insieme incredibilmente diversificato di dispositivi le cui applicazioni precaricate a volte dichiarano il privilegio READ_LOGS. Di conseguenza, la registrazione direttamente in logcat è sconsigliata, in quanto più soggetta alla perdita di dati.
Assicurati che tutto il logging in logcat sia sanificato nelle versioni non di debug della tua applicazione. Rimuovi tutti i dati che potrebbero essere sensibili. Come ulteriore precauzione, utilizza strumenti come R8 per rimuovere tutti i livelli di log, tranne avviso ed errore. Se hai bisogno di log più dettagliati, utilizza la memoria interna e gestisci i tuoi log direttamente, anziché utilizzare il log di sistema.
Impatto
La gravità della classe di vulnerabilità Log Info Disclosure può variare a seconda del contesto e del tipo di dati sensibili.Nel complesso, l'impatto di questa classe di vulnerabilità è la perdita di riservatezza di informazioni potenzialmente critiche come PII e credenziali
Mitigazioni
Generale
Come misura preventiva generale durante la progettazione e l'implementazione, definisci i limiti di attendibilità in base al principio del privilegio minimo. Idealmente, i dati sensibili non dovrebbero attraversare o raggiungere nessuna delle aree di attendibilità. Ciò rafforza la separazione dei privilegi.
Non registrare dati sensibili. Registra solo le costanti di compilazione, se possibile. Puoi utilizzare lo strumento ErrorProne per l'annotazione costante in fase di compilazione.
Evita i log che stampano istruzioni che potrebbero contenere informazioni impreviste, inclusi dati sensibili, a seconda dell'errore attivato. Per quanto possibile, i dati stampati nei log e nei log degli errori devono includere solo informazioni prevedibili.
Evita di accedere a logcat. Questo perché la registrazione in logcat potrebbe diventare un problema di privacy a causa delle app con l'autorizzazione READ_LOGS. Inoltre, non è efficace perché non può attivare avvisi o essere interrogato. Consigliamo alle applicazioni di configurare il backend logcat solo per le build per sviluppatori.
La maggior parte delle librerie di gestione dei log consente di definire i livelli di log, il che consente di registrare quantità diverse di informazioni tra i log di debug e di produzione. Modifica il livello di log in modo che sia diverso da "debug" non appena terminano i test del prodotto.
Rimuovi il maggior numero possibile di livelli di log dalla produzione. Se non puoi evitare di conservare i log in produzione, rimuovi le variabili non costanti dalle istruzioni di log. Possono verificarsi i seguenti scenari:
- Puoi rimuovere tutti i log dalla produzione.
- Devi conservare i log di avviso ed errore in produzione.
In entrambi i casi, rimuovi automaticamente i log utilizzando librerie come R8. Qualsiasi tentativo di rimozione manuale dei log è soggetto a errori. Nell'ambito dell'ottimizzazione del codice, R8 può essere impostato per rimuovere in modo sicuro i livelli di log che vuoi conservare per il debug, ma eliminare in produzione.
Se vuoi accedere alla produzione, prepara i flag che puoi utilizzare per disattivare la registrazione in modo condizionale in caso di incidente. I flag di risposta agli incidenti devono dare la priorità a: sicurezza del deployment; velocità e facilità di deployment, completezza dell'oscuramento dei log, memoria utilizzata e costi di prestazioni della scansione di ogni messaggio di log.
Rimuovi i log in logcat dalle build di produzione utilizzando R8.
In Android Studio 3.4 o nel plug-in Android per Gradle 3.4.0 e versioni successive, R8 è il compilatore predefinito per l'ottimizzazione e la riduzione del codice. Tuttavia, devi abilitare R8.
R8 ha sostituito ProGuard, ma il file delle regole nella cartella principale del progetto si chiama ancora proguard-rules.pro.Il seguente snippet mostra un file proguard-rules.pro di esempio che rimuove tutti i log dalla produzione tranne gli avvisi e gli errori:
-assumenosideeffects class android.util.Log {
private static final String TAG = "MyTAG";
public static boolean isLoggable(java.lang.String, int);
public static int v(TAG, "My log as verbose");
public static int d(TAG, "My log as debug");
public static int i(TAG, "My log as information");
}
Il seguente file proguard-rules.pro di esempio rimuove tutti i log dalla produzione:
-assumenosideeffects class android.util.Log {
private static final String TAG = "MyTAG";
public static boolean isLoggable(java.lang.String, int);
public static int v(TAG, "My log as verbose");
public static int d(TAG, "My log as debug");
public static int i(TAG, "My log as information");
public static int w(TAG, "My log as warning");
public static int e(TAG, "My log as error");
}
Tieni presente che R8 offre funzionalità di riduzione delle app e di rimozione dei log. Se vuoi utilizzare R8 solo per la funzionalità di rimozione dei log, aggiungi quanto segue al file proguard-rules.pro:
-dontwarn **
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!code/allocation/variable
-keep class **
-keepclassmembers class *{*;}
-keepattributes *
Elimina eventuali log in produzione contenenti dati sensibili
Per evitare la divulgazione di dati sensibili, assicurati che tutti i log in logcat siano sanificati nelle versioni non di debug della tua applicazione. Rimuovi tutti i dati che potrebbero essere sensibili.
Esempio:
Kotlin
data class Credential<T>(val data: String) {
/** Returns a redacted value to avoid accidental inclusion in logs. */
override fun toString() = "Credential XX"
}
fun checkNoMatches(list: List<Any>) {
if (!list.isEmpty()) {
Log.e(TAG, "Expected empty list, but was %s", list)
}
}
Java
public class Credential<T> {
private T t;
/** Returns a redacted value to avoid accidental inclusion in logs. */
public String toString(){
return "Credential XX";
}
}
private void checkNoMatches(List<E> list) {
if (!list.isEmpty()) {
Log.e(TAG, "Expected empty list, but was %s", list);
}
}
Oscura i dati sensibili nei log
Se devi includere dati sensibili nei log, ti consigliamo di sanificarli prima di stamparli per rimuovere o offuscare i dati sensibili. Per farlo, utilizza una delle seguenti tecniche:
- Tokenizzazione. Se i dati sensibili sono archiviati in un vault, ad esempio un sistema di gestione della crittografia da cui è possibile fare riferimento ai secret tramite token, registra il token anziché i dati sensibili.
- Mascheramento dei dati. La mascheratura dei dati è un processo irreversibile unidirezionale. Crea una versione dei dati sensibili che ha una struttura simile a quella originale, ma nasconde le informazioni più sensibili contenute in un campo. Esempio: sostituzione del numero carta
1234-5678-9012-3456conXXXX-XXXX-XXXX-1313. Prima di rilasciare l'app in produzione, ti consigliamo di completare una procedura di revisione della sicurezza per esaminare attentamente l'utilizzo della maschera dei dati. Avviso:non utilizzare la mascheratura dei dati nei casi in cui anche la divulgazione di una sola parte dei dati sensibili può influire in modo significativo sulla sicurezza, ad esempio quando vengono gestite le password. - Oscuramento. La redazione è simile alla mascheratura, ma nasconde tutte le informazioni contenute in un campo. Esempio: sostituzione del numero carta
1234-5678-9012-3456conXXXX-XXXX-XXXX-XXXX. - Filtri. Implementa le stringhe di formato nella libreria di logging che preferisci, se non esistono già, per facilitare la modifica dei valori non costanti nelle istruzioni di log.
La stampa dei log deve essere eseguita solo tramite un componente "logs sanitizer" che garantisce che tutti i log vengano sanificati prima della stampa, come mostrato nello snippet di codice seguente.
Kotlin
data class ToMask<T>(private val data: T) {
// Prevents accidental logging when an error is encountered.
override fun toString() = "XX"
// Makes it more difficult for developers to invoke sensitive data
// and facilitates sensitive data usage tracking.
fun getDataToMask(): T = data
}
data class Person(
val email: ToMask<String>,
val username: String
)
fun main() {
val person = Person(
ToMask("name@gmail.com"),
"myname"
)
println(person)
println(person.email.getDataToMask())
}
Java
public class ToMask<T> {
// Prevents accidental logging when an error is encountered.
public String toString(){
return "XX";
}
// Makes it more difficult for developers to invoke sensitive data
// and facilitates sensitive data usage tracking.
public T getDataToMask() {
return this;
}
}
public class Person {
private ToMask<String> email;
private String username;
public Person(ToMask<String> email, String username) {
this.email = email;
this.username = username;
}
}
public static void main(String[] args) {
Person person = new Person(
ToMask("name@gmail.com"),
"myname"
);
System.out.println(person);
System.out.println(person.email.getDataToMask());
}