Introdução
Kotlin é uma linguagem de programação moderna, amplamente utilizada para desenvolvimento de aplicativos Android, soluções de servidor (Ktor, Spring Boot) e projetos multiplataforma. Apesar de sua tipagem forte e segurança contra null, os desenvolvedores frequentemente cometem erros que levam a vulnerabilidades graves. Neste artigo, abordaremos o top 10 de vulnerabilidades em aplicações Kotlin, baseadas nos padrões OWASP, e mostraremos como evitá-las.
O artigo será útil tanto para desenvolvedores Kotlin iniciantes quanto para os experientes que desejam aumentar o nível de segurança de seus projetos.
1. Injeção de SQL (SQL Injection)
Problema: Inserção de código SQL malicioso através da entrada do usuário.
Exemplo de código vulnerável:
// Vulnerável! Não use concatenação de stringsfun getUserById(id: String): User? { val query = "SELECT * FROM users WHERE id = '$id'" val result = connection.createStatement().executeQuery(query) return result.toUser()}Solução: Use consultas parametrizadas (PreparedStatement).
// Segurofun getUserById(id: String): User? { val query = "SELECT * FROM users WHERE id = ?" val preparedStatement = connection.prepareStatement(query) preparedStatement.setString(1, id) val result = preparedStatement.executeQuery() return result.toUser()}2. Cross-Site Scripting (XSS)
Problema: Inserção de código JavaScript malicioso em uma página web.
Exemplo de código vulnerável (Ktor):
// Vulnerável! Não escape a saídaget("/search") { val query = call.parameters["q"] ?: "" call.respondHtml { h1 { +"Resultados da busca para: $query" } // XSS! }}Solução: Use escape HTML (por exemplo, kotlinx.html com escape).
// Seguroimport kotlinx.html.escapeHtml
get("/search") { val query = call.parameters["q"] ?: "" val safeQuery = query.escapeHtml() call.respondHtml { h1 { +"Resultados da busca para: $safeQuery" } }}3. Armazenamento inseguro de senhas
Problema: Armazenar senhas em texto puro ou usando hashes fracos (MD5, SHA-1).
Exemplo de código vulnerável:
// Vulnerável! MD5 não é adequado para senhasfun saveUser(password: String) { val hash = MessageDigest.getInstance("MD5").digest(password.toByteArray()) // salva o hash no BD}Solução: Use bcrypt, scrypt ou Argon2.
// Seguro (usando a biblioteca jbcrypt)import org.mindrot.jbcrypt.BCrypt
fun hashPassword(password: String): String { return BCrypt.hashpw(password, BCrypt.gensalt(12))}
fun checkPassword(password: String, hashed: String): Boolean { return BCrypt.checkpw(password, hashed)}4. Vazamento de dados confidenciais através de logs
Problema: Registrar senhas, tokens, números de cartão.
Exemplo de código vulnerável:
// Vulnerável! Registrando dados sensíveisfun login(username: String, password: String) { log.info("Tentativa de login: username=$username, password=$password")}Solução: Use filtros ou mascaramento.
// Segurofun login(username: String, password: String) { log.info("Tentativa de login: username=$username") // password não é registrado}5. Desserialização insegura
Problema: Execução de código arbitrário ao desserializar dados não verificados.
Exemplo de código vulnerável:
// Vulnerável! Desserialização sem verificaçãofun process
```