Segurança de aplicações Kotlin: top 10 vulnerabilidades na prática
Kotlin ocupa com confiança uma das posições de linguagens mais populares para desenvolvimento Android e aplicações servidoras. No entanto, como qualquer outra linguagem, Kotlin não está imune a vulnerabilidades. Neste artigo, analisaremos as 10 principais questões críticas de segurança que os desenvolvedores enfrentam e mostraremos como evitá-las na prática.
1. Injeção de SQL (SQL Injection)
Apesar de Kotlin ser frequentemente usado com bibliotecas ORM, o trabalho direto com consultas SQL continua sendo uma prática comum.
Código vulnerável:
fun getUser(id: String): User? { val query = "SELECT * FROM users WHERE id = '$id'" val result = connection.createStatement().executeQuery(query) // ...}Versão segura (usando PreparedStatement):
fun getUserSafe(id: String): User? { val query = "SELECT * FROM users WHERE id = ?" val stmt = connection.prepareStatement(query) stmt.setString(1, id) val result = stmt.executeQuery() // ...}Conclusão: Nunca concatene entrada do usuário em consultas SQL. Use consultas parametrizadas ou ORM (Exposed, Hibernate).
2. Cross-Site Scripting (XSS) em aplicações Web
Ao desenvolver aplicações servidoras com Ktor ou Spring Boot, frequentemente esquecem de escapar a saída.
Código vulnerável (Ktor):
get("/user/{name}") { val name = call.parameters["name"] ?: "Convidado" call.respondText("<h1>Olá, $name!</h1>", ContentType.Text.Html)}Versão segura:
import org.apache.commons.text.StringEscapeUtils
get("/user/{name}") { val name = call.parameters["name"] ?: "Convidado" val safeName = StringEscapeUtils.escapeHtml4(name) call.respondText("<h1>Olá, $safeName!</h1>", ContentType.Text.Html)}Dica: Sempre escape a entrada do usuário antes de exibir em HTML. Use mecanismos de template com auto-escape (por exemplo, Kotlinx.html).
3. Armazenamento inseguro de senhas
Armazenar senhas em texto claro ou usando hashes fracos é um dos erros mais comuns.
Abordagem incorreta:
fun savePassword(password: String) { val hash = password.md5() // Nunca faça isso! database.saveHash(hash)}Abordagem correta (bcrypt):
import at.favre.lib.crypto.bcrypt.BCrypt
fun savePassword(password: String) { val hash = BCrypt.withDefaults().hashToString(12, password.toCharArray()) database.saveHash(hash)}
fun checkPassword(password: String, storedHash: String): Boolean { return BCrypt.verifyer().verify(password.toCharArray(), storedHash).verified}Importante: Use bcrypt, scrypt ou Argon2. Nunca use MD5 ou SHA-1 para armazenar senhas.
4. Vazamento de dados confidenciais através de logs
Desenvolvedores frequentemente registram dados sensíveis sem verificar o que está sendo exibido.
Código problemático:
logger.info("Usuário $userId autenticado com token: $token")Versão segura:
logger.info("Usuário $userId autenticado com sucesso")// Ou use mascaramento:fun maskToken(token: String): String = token.take(4) + "****" + token.takeLast(4)Regra: Nunca registre em logs senhas, tokens, números de cartão de crédito ou dados pessoais. Use bibliotecas de mascaramento (por exemplo, Logstash).
5. Desserialização insegura
Kotlin usa ativamente serialização JSON. Configuração incorreta pode levar a ataques RCE.
Código vulnerável (Jackson):
val mapper = ObjectMapper()val obj = mapper.readValue(userInput, Any::class.j