Sécurité des applications Swift : top 10 des vulnérabilités en pratique
Le développement d'applications mobiles pour iOS et macOS nécessite une attention particulière à la sécurité. Swift est un langage puissant et moderne, mais même lui ne protège pas le développeur des erreurs typiques qui peuvent entraîner des fuites de données, un piratage ou des pertes financières. Dans cet article, nous analyserons le top 10 des vulnérabilités des applications Swift avec des exemples de code réels et des recommandations pratiques pour les corriger.
1. Injections SQL via Core Data et SQLite
De nombreux développeurs utilisent des requêtes SQL brutes avec SQLite. Si les données de l'utilisateur ne sont pas échappées, un attaquant peut exécuter une requête arbitraire sur la base de données.
// ❌ Code vulnérablelet query = "SELECT * FROM users WHERE name = '\\(userInput)'"
// ✅ Code sécurisé (utilisation de requêtes paramétrées)let query = "SELECT * FROM users WHERE name = ?"var statement: OpaquePointer?sqlite3_prepare_v2(database, query, -1, &statement, nil)sqlite3_bind_text(statement, 1, (userInput as NSString).utf8String, -1, nil)Utilisez des requêtes paramétrées ou Core Data avec des prédicats – cela élimine les injections.
2. Stockage non sécurisé des données dans Keychain
Keychain est un endroit sécurisé, mais de nombreux développeurs configurent mal les attributs d'accès. Par exemple, si kSecAttrAccessible n'est pas spécifié, les données peuvent être accessibles après une sauvegarde.
// ❌ Code vulnérable (accessible après sauvegarde)let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: "token", kSecValueData as String: tokenData]
// ✅ Code sécurisé (uniquement lorsque l'appareil est déverrouillé)let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: "token", kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly, kSecValueData as String: tokenData]3. Absence de vérification SSL/TLS (Man-in-the-Middle)
Lors du développement, la vérification des certificats est souvent désactivée pour les tests, mais on oublie de rétablir les paramètres dans la version finale. Cela permet à un attaquant d'intercepter le trafic.
// ❌ Code vulnérable (dangereux pour la production)let session = URLSession(configuration: .default, delegate: self, delegateQueue: nil)// Dans le délégué :func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))}
// ✅ Code sécurisé – utilisez la vérification standardlet session = URLSession.shared// Ou utilisez ATS (App Transport Security) dans Info.plistActivez App Transport Security (ATS) et ne le désactivez pas dans la version de production.
4. Fuite de données via les logs et Crashlytics
Les développeurs journalisent souvent des données sensibles (jetons, mots de passe) pour le débogage. Si le log parvient à un service tiers (par exemple, Firebase Crashlytics), les données fuient.
// ❌ Code vulnérableprint("User token: \\(userToken)")
// ✅ Code sécurisé#if DEBUG print("User token: [REDACTED]")#endif// Ou utilisez os_log avec un niveau de confidentialitéos_log("User token: %{private}@", log: .default, type: .debug, userToken)Ne journalisez jamais de données sensibles en production. Utilisez le masquage ou la compilation conditionnelle.
5. Stockage non sécurisé des secrets dans le code
Stocker des clés API, des jetons et des mots de passe directement dans le code source est une erreur grossière. Même si le code est obscurci, les chaînes sont faciles à extraire du fichier binaire.
// ❌ Code vulnérablelet apiKey = "sk-1234567890abcdef"
// ✅ Code sécurisé – utilisez l'authentification côté serveur// Ou chiffrez les clés avec CryptoKitimport CryptoKitlet key = SymmetricKey(data: "server_