Categoria OWASP: MASVS-CODE: Qualità del codice
Panoramica
Non è raro vedere applicazioni che implementano funzionalità che consentono agli utenti di Trasferire dati o interagire con altri dispositivi utilizzando le radiofrequenze (RF) comunicazioni o connessioni cablate. Le tecnologie più comuni utilizzate in I dispositivi Android a questo scopo sono Bluetooth classico (Bluetooth BR/EDR), Bluetooth Low Energia (BLE), Wi-Fi P2P, NFC e USB.
Queste tecnologie vengono in genere implementate in applicazioni che dovrebbero comunicare con accessori per la smart home, dispositivi di monitoraggio della salute, chioschi per il trasporto pubblico, terminali di pagamento e altri dispositivi basati su Android.
Come per qualsiasi altro canale, le comunicazioni machine-to-machine sono soggette a attacchi volti a compromettere il confine di attendibilità stabilito tra due o più dispositivi. Tecniche come la rappresentazione di un dispositivo possono essere sfruttate da utenti malintenzionati per eseguire un numero elevato di attacchi contro il canale di comunicazione.
Android mette a disposizione degli sviluppatori API specifiche per la configurazione delle comunicazioni macchina-a-macchina.
Queste API devono essere utilizzate con cautela come errori durante l'implementazione della comunicazione dei protocolli può comportare l'esposizione dei dati dell'utente o del dispositivo a e terze parti. Nel peggiore dei casi, gli aggressori potrebbero riuscire a eseguire operazioni assumere il controllo di uno o più dispositivi, ottenendo di conseguenza l'accesso completo ai contenuti sul dispositivo.
Impatto
L'impatto può variare in base alla tecnologia da dispositivo a dispositivo implementata in per l'applicazione.
Utilizzo o configurazione non corretto del processo da macchina a macchina canali di comunicazione potrebbero lasciare il dispositivo dell'utente esposto a non attendibili tentativi di comunicazione. Questo può rendere il dispositivo vulnerabile a come attacchi man in the middle (MiTM), command injection, DoS o attacchi di impersonificazione.
Rischio: intercettazione di dati sensibili tramite canali wireless
Quando implementi meccanismi di comunicazione tra macchine, è necessario considerare sia la tecnologia utilizzata sia il tipo di dati che devono essere trasmessi. Sebbene le connessioni via cavo siano in pratica più sicure per queste attività, in quanto richiedono un collegamento fisico tra i dispositivi coinvolti, i protocolli di comunicazione che utilizzano frequenze radio come il Bluetooth classico, BLE, NFC e il Wi-Fi P2P possono essere intercettati. Un malintenzionato potrebbe essere in grado di rubare l'identità di uno dei terminali o dei punti di accesso coinvolti nello scambio di dati, intercettando la comunicazione via etere e ottenendo così l'accesso a dati sensibili degli utenti. Inoltre, le applicazioni dannose installate sul dispositivo, se concesse le autorizzazioni di runtime specifiche della comunicazione, potrebbero essere in grado di recuperare i dati scambiati tra i dispositivi leggendo i buffer dei messaggi di sistema.
Mitigazioni
Se l'applicazione richiede lo scambio di dati sensibili tra macchine su canali wireless, le soluzioni di sicurezza a livello di applicazione, come la crittografia, devono essere implementate nel codice dell'applicazione. In questo modo, gli utenti malintenzionati non potranno eseguire attività di sniffing sul canale di comunicazione e recuperare i dati scambiati in testo non criptato. Per risorse aggiuntive, consulta Crittografia.
Rischio: inserimento di dati dannosi tramite rete wireless
Canali di comunicazione wireless tra macchina (Bluetooth classico, BLE, NFC, Wifi P2P) possono essere manomessi usando dati dannosi. Competenza sufficiente i malintenzionati possono identificare il protocollo di comunicazione in uso e manomettere flusso di scambio di dati, ad esempio simulando l'identità di uno degli endpoint, appositamente creati. Questo tipo di traffico dannoso potrebbe peggiorare la funzionalità dell'applicazione e, nel peggiore dei casi, causare comportamenti imprevisti dell'applicazione e del dispositivo o attacchi come DoS, attacco di comando o compromissione del dispositivo.
Mitigazioni
Android fornisce agli sviluppatori API potenti per gestire comunicazioni tra macchina, come Bluetooth classico, BLE, NFC e Wi-Fi P2P. Questi dovrebbero essere combinati con una logica di convalida dei dati accuratamente implementata per sanificare i dati scambiati tra i due dispositivi.
Questa soluzione deve essere implementata a livello di applicazione e deve includere controlli che verificano se i dati hanno la lunghezza e il formato previsti e se contengono un payload valido che può essere interpretato dall'applicazione.
Lo snippet seguente mostra un esempio di logica di convalida dei dati. Questa funzionalità è stata implementata rispetto all'esempio di implementazione dei dati Bluetooth per gli sviluppatori Android trasferimento:
Kotlin
class MyThread(private val mmInStream: InputStream, private val handler: Handler) : Thread() {
private val mmBuffer = ByteArray(1024)
override fun run() {
while (true) {
try {
val numBytes = mmInStream.read(mmBuffer)
if (numBytes > 0) {
val data = mmBuffer.copyOf(numBytes)
if (isValidBinaryData(data)) {
val readMsg = handler.obtainMessage(
MessageConstants.MESSAGE_READ, numBytes, -1, data
)
readMsg.sendToTarget()
} else {
Log.w(TAG, "Invalid data received: $data")
}
}
} catch (e: IOException) {
Log.d(TAG, "Input stream was disconnected", e)
break
}
}
}
private fun isValidBinaryData(data: ByteArray): Boolean {
if (// Implement data validation rules here) {
return false
} else {
// Data is in the expected format
return true
}
}
}
Java
public void run() {
mmBuffer = new byte[1024];
int numBytes; // bytes returned from read()
// Keep listening to the InputStream until an exception occurs.
while (true) {
try {
// Read from the InputStream.
numBytes = mmInStream.read(mmBuffer);
if (numBytes > 0) {
// Handle raw data directly
byte[] data = Arrays.copyOf(mmBuffer, numBytes);
// Validate the data before sending it to the UI activity
if (isValidBinaryData(data)) {
// Data is valid, send it to the UI activity
Message readMsg = handler.obtainMessage(
MessageConstants.MESSAGE_READ, numBytes, -1,
data);
readMsg.sendToTarget();
} else {
// Data is invalid
Log.w(TAG, "Invalid data received: " + data);
}
}
} catch (IOException e) {
Log.d(TAG, "Input stream was disconnected", e);
break;
}
}
}
private boolean isValidBinaryData(byte[] data) {
if (// Implement data validation rules here) {
return false;
} else {
// Data is in the expected format
return true;
}
}
Rischio: inserimento di dati dannosi tramite USB
Le connessioni USB tra due dispositivi potrebbero essere prese di mira da un utente malintenzionato interessati a intercettare le comunicazioni. In questo caso, il collegamento fisico richiesto costituisce un ulteriore livello di sicurezza, in quanto l'aggressore deve ottenere l'accesso al cavo che collega i terminali per poter intercettare qualsiasi messaggio. Un altro vettore di attacco è rappresentato da dispositivi USB non attendibili che, intenzionalmente o meno, sono collegati al dispositivo.
Se l'applicazione filtra i dispositivi USB utilizzando PID/VID per l'attivazione di specifiche funzionalità in-app, i malintenzionati potrebbero essere in grado di manomettere i dati inviati canale USB simulando l'identità del dispositivo legittimo. Attacchi di questo tipo possono Consentire a utenti malintenzionati di inviare sequenze di tasti al dispositivo o di eseguire applicazioni attività che, nel peggiore dei casi, possono portare all'esecuzione di codice in remoto download di software indesiderato.
Mitigazioni
Deve essere implementata una logica di convalida a livello di applicazione. Questa logica dovrebbe filtrare i dati inviati tramite USB controllando che la lunghezza, il formato e i contenuti corrispondano al caso d'uso dell'applicazione. Ad esempio, un monitor per il battito cardiaco non deve essere in grado di inviare comandi di battitura.
Inoltre, se possibile, occorre considerare la limitazione di pacchetti USB che l'applicazione può ricevere dal dispositivo USB. Questo impedisce ai dispositivi dannosi di eseguire attacchi come la paperella di gomma.
Questa convalida può essere eseguita creando un nuovo thread per controllare i contenuti del buffer, ad esempio su un bulkTransfer
:
Kotlin
fun performBulkTransfer() {
// Stores data received from a device to the host in a buffer
val bytesTransferred = connection.bulkTransfer(endpointIn, buffer, buffer.size, 5000)
if (bytesTransferred > 0) {
if (//Checks against buffer content) {
processValidData(buffer)
} else {
handleInvalidData()
}
} else {
handleTransferError()
}
}
Java
public void performBulkTransfer() {
//Stores data received from a device to the host in a buffer
int bytesTransferred = connection.bulkTransfer(endpointIn, buffer, buffer.length, 5000);
if (bytesTransferred > 0) {
if (//Checks against buffer content) {
processValidData(buffer);
} else {
handleInvalidData();
}
} else {
handleTransferError();
}
}
Rischi specifici
Questa sezione raccoglie i rischi che richiedono strategie di mitigazione non standard o che sono stati mitigati a un determinato livello di SDK e sono riportati per completezza.
Rischio: Bluetooth - tempo di rilevabilità errato
Come evidenziato nella documentazione relativa al Bluetooth per gli sviluppatori Android, mentre
configurando l'interfaccia Bluetooth all'interno dell'applicazione, utilizzando
Metodo startActivityForResult(Intent, int)
per attivare il dispositivo
la rilevabilità e l'impostazione di EXTRA_DISCOVERABLE_DURATION
su zero
il dispositivo sarà rilevabile fintanto che l'applicazione è in esecuzione
in primo piano o sullo sfondo. Come per le specifiche del Bluetooth classico, i dispositivi rilevabili trasmettono costantemente informazioni specifiche
messaggi che consentono ad altri dispositivi di recuperare i dati del dispositivo o di connettersi al dispositivo. Nel
in uno scenario di questo tipo, una terza parte dannosa può intercettare questi messaggi e connettersi
sul dispositivo Android. Una volta connesso, un malintenzionato può eseguire ulteriori attacchi come furto di dati, DoS o attacco di iniezione di comandi.
Mitigazioni
EXTRA_DISCOVERABLE_DURATION
non deve mai essere impostato su zero. Se il parametro EXTRA_DISCOVERABLE_DURATION
non è impostato, per impostazione predefinita Android rende i dispositivi rilevabili per 2 minuti. Il valore massimo che può essere impostato per l'attributo
Il parametro EXTRA_DISCOVERABLE_DURATION
dura 2 ore (7200 secondi). È
consigliato per limitare il tempo di rilevabilità al tempo più breve
possibili, in base al caso d'uso dell'applicazione.
Rischio: NFC - filtri intent clonati
Un'applicazione dannosa può registrare filtri intent per leggere tag NFC o dispositivi con tecnologia NFC specifici. Questi filtri possono replicare quelli definiti da un'applicazione legittima, consentendo a un malintenzionato di leggere i contenuti dei dati NFC scambiati. È opportuno notare che, quando due attività specificano gli stessi filtri intent per un tag NFC specifico, viene visualizzato il Selettore di attività, pertanto l'utente dovrà comunque scegliere l'applicazione dannosa affinché l'attacco vada a buon fine. Tuttavia, combinando filtri per intent con il cloaking, questo scenario è ancora possibile. Questo attacco è significativo solo nei casi in cui i dati scambiati tramite NFC possono essere considerati molto sensibile.
Mitigazioni
Quando implementi funzionalità di lettura NFC all'interno di un'applicazione, i filtri intent possono essere utilizzati insieme ai record delle applicazioni Android (AAR). Incorporando il Il record AAR all'interno di un messaggio NDEF dà la forte garanzia che solo il legittima e l'attività di gestione NDEF associata, viene avviata. In questo modo, le applicazioni o le attività indesiderate non potranno leggere i dati dei tag o dei dispositivi altamente sensibili scambiati tramite NFC.
Rischio: NFC - Mancanza di convalida dei messaggi NDEF
Quando un dispositivo Android riceve dati da un tag NFC o da un dispositivo con NFC abilitato, il sistema attiva automaticamente l'applicazione o l'attività specifica configurata per gestire il messaggio NDEF al suo interno. In base alla logica implementata nell'applicazione, i dati contenuti nel tag o ricevuti dal dispositivo possono essere inviati ad altre attività per attivare ulteriori azioni, come l'apertura di pagine web.
Un’applicazione priva della convalida dei contenuti dei messaggi NDEF potrebbe consentire agli utenti malintenzionati di utilizzano dispositivi abilitati per NFC o tag NFC per iniettare payload dannosi all’interno causando un comportamento imprevisto che potrebbe causare file dannosi download, command injection o DoS.
Mitigazioni
Prima di inviare il messaggio NDEF ricevuto a qualsiasi altro componente dell'applicazione, i dati al suo interno devono essere convalidati per verificare che siano nel formato previsto e che contengano le informazioni previste. In questo modo eviterai che i dati dannosi vengano trasmessi ad altri delle applicazioni componenti non filtrati, riducendo il rischio di comportamenti imprevisti attacchi che utilizzano dati NFC manomessi.
Lo snippet seguente mostra un esempio di logica di convalida dei dati implementata come metodo con un messaggio NDEF come argomento e il relativo indice nell'array di messaggi. Questa funzionalità è stata implementata nell'esempio degli sviluppatori Android per ottenere dati da una tag NDEF NFC scansionato:
Kotlin
//The method takes as input an element from the received NDEF messages array
fun isValidNDEFMessage(messages: Array<NdefMessage>, index: Int): Boolean {
// Checks if the index is out of bounds
if (index < 0 || index >= messages.size) {
return false
}
val ndefMessage = messages[index]
// Retrieves the record from the NDEF message
for (record in ndefMessage.records) {
// Checks if the TNF is TNF_ABSOLUTE_URI (0x03), if the Length Type is 1
if (record.tnf == NdefRecord.TNF_ABSOLUTE_URI && record.type.size == 1) {
// Loads payload in a byte array
val payload = record.payload
// Declares the Magic Number that should be matched inside the payload
val gifMagicNumber = byteArrayOf(0x47, 0x49, 0x46, 0x38, 0x39, 0x61) // GIF89a
// Checks the Payload for the Magic Number
for (i in gifMagicNumber.indices) {
if (payload[i] != gifMagicNumber[i]) {
return false
}
}
// Checks that the Payload length is, at least, the length of the Magic Number + The Descriptor
if (payload.size == 13) {
return true
}
}
}
return false
}
Java
//The method takes as input an element from the received NDEF messages array
public boolean isValidNDEFMessage(NdefMessage[] messages, int index) {
//Checks if the index is out of bounds
if (index < 0 || index >= messages.length) {
return false;
}
NdefMessage ndefMessage = messages[index];
//Retrieve the record from the NDEF message
for (NdefRecord record : ndefMessage.getRecords()) {
//Check if the TNF is TNF_ABSOLUTE_URI (0x03), if the Length Type is 1
if ((record.getTnf() == NdefRecord.TNF_ABSOLUTE_URI) && (record.getType().length == 1)) {
//Loads payload in a byte array
byte[] payload = record.getPayload();
//Declares the Magic Number that should be matched inside the payload
byte[] gifMagicNumber = {0x47, 0x49, 0x46, 0x38, 0x39, 0x61}; // GIF89a
//Checks the Payload for the Magic Number
for (int i = 0; i < gifMagicNumber.length; i++) {
if (payload[i] != gifMagicNumber[i]) {
return false;
}
}
//Checks that the Payload length is, at least, the length of the Magic Number + The Descriptor
if (payload.length == 13) {
return true;
}
}
}
return false;
}
Risorse
- Autorizzazioni di runtime
- Guide alla connettività
- Esempio
- bulkTransfer
- Crittografia
- Configurare il Bluetooth
- NFC Basis
- Record delle app Android
- Specifiche Bluetooth classico