Seguridad en Swift: Inyecciones SQL y XSS — cómo proteger el código

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Swift en primera línea: por qué la seguridad no es una opción, sino una necesidad

\n

Escribes en Swift, te enorgulleces del rendimiento y la belleza del código. Pero ¿alguna vez te has preguntado qué tan vulnerable es tu aplicación a ataques? Las inyecciones SQL y XSS (Cross-Site Scripting) no son solo historias de terror de los libros de texto. Son amenazas reales que pueden costarte datos de usuarios, reputación y dinero.

\n

En este artículo, analizaremos cómo proteger una aplicación Swift (ya sea un cliente iOS o una parte del servidor con Vapor) contra los dos tipos de ataques más peligrosos. Sin rodeos: solo ejemplos prácticos, soluciones listas y código real. ¡Allá vamos!

\n\n

Inyecciones SQL en Swift: cómo los hackers «engañan» a la base de datos

\n

Imagina: un usuario escribe en un campo de texto '; DROP TABLE Users; --. Si insertas directamente esta cadena en una consulta SQL, la base de datos ejecutará el comando de eliminación. Un clásico del género.

\n

En Swift, esta vulnerabilidad se encuentra más a menudo en frameworks del lado del servidor (Vapor, Kitura) o al trabajar con Core Data y SQLite a través de envoltorios inseguros.

\n\n

Ejemplo peligroso: cómo NO hacerlo

\n
import SQLite\n\nlet username = userInput.text // "admin' OR '1'='1"\nlet query = "SELECT * FROM users WHERE name = '\\(username)'"\ntry db.execute(query) // ¡AMENAZA! Consulta comprometida\n
\n

Este código es una bandera roja. Un atacante puede obtener acceso a cualquier dato o destruir la tabla.

\n\n

Enfoque correcto: consultas parametrizadas

\n

Regla de oro: nunca insertes datos de usuario directamente en una cadena de consulta. Usa parametrización.

\n
import SQLite\n\nlet db = try Connection("path/to/db.sqlite3")\nlet users = Table("users")\nlet name = Expression<String>("name")\n\nlet username = userInput.text // "admin' OR '1'='1"\nlet query = users.filter(name == username) // SEGURO\nlet result = try db.prepare(query)\n
\n

La librería SQLite.swift escapa los caracteres especiales automáticamente. Para Vapor con Fluent, usa el modelo y filtros:

\n
import Fluent\nimport Vapor\n\nstruct UserController: RouteCollection {\n    func login(req: Request) async throws -> String {\n        let input = try req.content.decode(LoginRequest.self)\n        // Fluent parametriza automáticamente la consulta\n        let user = try await User.query(on: req.db)\n            .filter(\\.$name == input.username)\n            .first()\n        return user?.name ?? "Not found"\n    }\n}\n
\n

Importante: incluso si usas SQL raw en Vapor, aplica SQLBind para vincular parámetros.

\n\n

ORM y Core Data: la ilusión de seguridad

\n

Muchos desarrolladores creen que Core Data o Fluent protegen automáticamente contra inyecciones. Esto es cierto, siempre que no uses NSExpression con formato de cadenas o SQL raw. Pero recuerda: cualquier NSPredicate construido mediante interpolación de cadenas es un riesgo.

\n
// PELIGROSO\nlet predicate = NSPredicate(format: "name == %@", userInput) // ¿Seguro?\n// ¡NO! Si userInput contiene '%', puede ocurrir una inyección mediante sustitución.\n
\n

Siempre usa %@ con variables, no %K con claves, y nunca insertes cadenas mediante \\().

\n\n

Ataques XSS en Swift: cuando el atacante inyecta JavaScript

\n

XSS es un ataque en el que un script malicioso se ejecuta en el navegador del usuario. Para aplicaciones iOS, XSS es relevante al usar WKWebView para mostrar contenido HTML (por ejemplo, en un feed de noticias o chats).

\n\n

Escenario real: chat con formato HTML

\n

Un usuario escribe: ¡Hola! <script>alert('XSS')</script>. Si muestras este mensaje en un WebView sin procesarlo, el script se ejecutará.

\n
// PELIGROSO\nlet html = "<div>\\(message.text)</div>"\nwebView.loadHTMLString(html, baseURL: nil)\n

Blogs

Book Recommendations