Su código bajo la mira: por qué la seguridad en Kotlin no es una opción, sino una necesidad
\n\nImagine: ha escrito una aplicación perfecta. Interfaz bonita, velocidad ultrarrápida, arquitectura limpia. Pero en una línea de código se esconde una "puerta trasera". Un atacante introduce en el campo de búsqueda ' OR '1'='1 — y su base de datos queda abierta como una lata de conservas. ¿Le suena? Si no — excelente. Pero es mejor estar preparado de antemano que apagar un incendio en producción.
Kotlin es un lenguaje potente y moderno. Pero, como cualquier otra herramienta, no hace que su código sea seguro por defecto. Las inyecciones SQL y XSS (Cross-Site Scripting) siguen estando en la cima del OWASP Top 10 desde hace muchos años. Y los desarrolladores de Kotlin que piensan "uso ORM, no corro peligro", a menudo terminan en la zona de riesgo.
\n\nEn este artículo, analizaremos cómo convertir su código Kotlin en una fortaleza inexpugnable. Sin rodeos — solo consejos prácticos, ejemplos reales y trucos que podrá aplicar hoy mismo.
\n\nInyecciones SQL en Kotlin: anatomía de un ataque y estrategias de defensa
\n\nCómo se ve una vulnerabilidad (y por qué da miedo)
\n\nUna inyección SQL ocurre cuando la entrada del usuario llega directamente a una consulta SQL. Supongamos que tiene este código (¡nunca lo haga!):
\n\nfun getUserById(id: String): User? {\n val query = "SELECT * FROM users WHERE id = '$id'"\n val statement = connection.createStatement()\n val result = statement.executeQuery(query)\n // ...\n}\n\nSi un atacante pasa id = "1'; DROP TABLE users; --", la base de datos ejecutará: SELECT * FROM users WHERE id = '1'; DROP TABLE users; --'. Y sus usuarios desaparecerán. Sin retorno.
Regla n.º 1: Use siempre consultas parametrizadas
\n\nEste es el estándar de oro. Kotlin (y Java) proporciona PreparedStatement, que separa el código SQL de los datos:
fun getUserByIdSafe(id: String): User? {\n val query = "SELECT * FROM users WHERE id = ?"\n val preparedStatement = connection.prepareStatement(query)\n preparedStatement.setString(1, id)\n val result = preparedStatement.executeQuery()\n // ...\n}\n\nLa base de datos recibe la plantilla de la consulta por separado de los datos. Incluso si en id llega código malicioso, se interpretará como una cadena, no como un comando.
Regla n.º 2: Use Exposed u otros ORM correctamente
\n\nLa biblioteca Exposed es una opción popular para Kotlin. Es segura si se usa su API correctamente. Ejemplo malo (concatenación cruda):
\n\n// MALO: vulnerable\nval users = transaction {\n exec("SELECT * FROM users WHERE name = '$userInput'")\n}\n\nEjemplo bueno (uso del DSL de Exposed):
\n\n// BUENO: escape incorporado\nval users = transaction {\n Users.select { Users.name eq userInput }\n}\n\nEn Exposed, el operador eq escapa automáticamente los valores. Pero si escribe consultas SQL crudas a través de exec — esté atento.
Regla n.º 3: Validación en la entrada — su segundo escudo
\n\nIncluso con consultas parametrizadas, no debe dejar pasar cualquier cosa a la base de datos. Use las herramientas integradas de Kotlin para verificar:
\n\nfun validateUserId(id: String): Boolean {\n // Verificamos que id sea un UUID o un número entero\n return id.matches(Regex("^[a-fA-F0-9-]{36}$")) || \n id.all { it.isDigit() }\n}\n\nRecuerde: no confíe en ninguna entrada. Incluso si proviene de su propio frontend. Especialmente si proviene de su propio frontend.
\n\nAtaques XSS: cómo evitar que el código JavaScript se apodere de su sitio
\n\nQué es XSS y por qué Kotlin no lo protege automáticamente
\n\nXSS (Cross-Site Scripting) es cuando un atacante inyecta un script en su página. Por ejemplo, en el campo de comentarios escribe: <script>alert('Sus datos han sido robados')</script>