Seguridad en aplicaciones Swift: top 10 vulnerabilidades y métodos de protección
El desarrollo en Swift para iOS y macOS requiere especial atención a la seguridad. Incluso un pequeño error puede provocar fugas de datos, hackeos o comprometer el dispositivo. En este artículo analizaremos las 10 vulnerabilidades más comunes en aplicaciones Swift, mostraremos ejemplos de código peligroso y daremos recomendaciones prácticas para solucionarlas.
1. Almacenamiento inseguro de datos (Insecure Data Storage)
El error más frecuente es guardar datos confidenciales en UserDefaults o archivos Plist sin cifrado.
Código problemático:
UserDefaults.standard.set("password123", forKey: "userPassword")UserDefaults.standard.synchronize()Solución segura: Utilice Keychain Services o Data Protection API.
import Security
func savePassword(_ password: String, for account: String) { let data = password.data(using: .utf8)! let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrAccount as String: account, kSecValueData as String: data, kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly ] SecItemAdd(query as CFDictionary, nil)}2. Falta de validación de entrada (Input Validation)
La entrada del usuario a menudo contiene datos maliciosos. Siempre verifique y sanitice la entrada.
Ejemplo de inyección SQL:
let query = "SELECT * FROM users WHERE name = '\\(userInput)'" // ¡Peligroso!Protección: Utilice consultas parametrizadas.
let query = "SELECT * FROM users WHERE name = ?"let statement = try database.prepare(query)try statement.bind([userInput])3. Comunicación de red insegura (Insecure Network Communication)
Uso de HTTP en lugar de HTTPS, ignorar certificados SSL.
Código peligroso:
let url = URL(string: "http://example.com/api")! // HTTP, no HTTPSlet task = URLSession.shared.dataTask(with: url) { data, response, error in // Procesamiento de datos}Enfoque seguro:
let url = URL(string: "https://example.com/api")!let config = URLSessionConfiguration.defaultconfig.tlsMinimumSupportedProtocolVersion = .TLSv12let session = URLSession(configuration: config)let task = session.dataTask(with: url) { data, response, error in guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { return } // Procesamiento de datos}task.resume()4. Inyección de código a través de WebView (WebView Injection)
Si utiliza WKWebView sin restricciones, un atacante puede ejecutar código JavaScript.
Código vulnerable:
webView.loadHTMLString(htmlContent, baseURL: nil)Protección: Desactive JavaScript o utilice Content Security Policy.
let config = WKWebViewConfiguration()let preferences = WKPreferences()preferences.javaScriptEnabled = falseconfig.preferences = preferenceslet webView = WKWebView(frame: .zero, configuration: config)5. Claves API y tokens no protegidos (Hardcoded Secrets)
Nunca almacene claves API, tokens o contraseñas en el código fuente.
Incorrecto:
let apiKey = "sk_live_1234567890abcdef"Correcto: Utilice archivos .env, autorización del servidor o servicios en la nube (por ejemplo, AWS Secrets Manager).
// En Info.plist clave cifradaif let apiKey = Bundle.main.object(forInfoDictionaryKey: "API_KEY") as? String { // Usamos la clave}