Sicherheit von Kotlin-Anwendungen: Die Top 10 Schwachstellen in der Praxis
Kotlin hat sich fest als eine der beliebtesten Sprachen für die Entwicklung von Android- und Serveranwendungen etabliert. Wie jede andere Sprache ist jedoch auch Kotlin nicht immun gegen Schwachstellen. In diesem Artikel analysieren wir die Top 10 der kritischsten Sicherheitsprobleme, mit denen Entwickler konfrontiert werden, und zeigen, wie man sie in der Praxis vermeidet.
1. SQL-Injection
Obwohl Kotlin häufig mit ORM-Bibliotheken verwendet wird, bleibt die direkte Arbeit mit SQL-Abfragen eine gängige Praxis.
Verwundbarer Code:
fun getUser(id: String): User? { val query = "SELECT * FROM users WHERE id = '$id'" val result = connection.createStatement().executeQuery(query) // ...}Sichere Version (Verwendung von 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() // ...}Fazit: Verketten Sie niemals Benutzereingaben in SQL-Abfragen. Verwenden Sie parametrisierte Abfragen oder ORM (Exposed, Hibernate).
2. Cross-Site Scripting (XSS) in Webanwendungen
Bei der Entwicklung von Serveranwendungen mit Ktor oder Spring Boot wird oft vergessen, die Ausgabe zu escapen.
Verwundbarer Code (Ktor):
get("/user/{name}") { val name = call.parameters["name"] ?: "Gast" call.respondText("<h1>Hallo, $name!</h1>", ContentType.Text.Html)}Sichere Version:
import org.apache.commons.text.StringEscapeUtils
get("/user/{name}") { val name = call.parameters["name"] ?: "Gast" val safeName = StringEscapeUtils.escapeHtml4(name) call.respondText("<h1>Hallo, $safeName!</h1>", ContentType.Text.Html)}Tipp: Escapen Sie Benutzereingaben immer vor der Ausgabe in HTML. Verwenden Sie Template-Engines mit Auto-Escaping (z. B. Kotlinx.html).
3. Unsichere Speicherung von Passwörtern
Die Speicherung von Passwörtern im Klartext oder mit schwachen Hashes ist einer der häufigsten Fehler.
Falscher Ansatz:
fun savePassword(password: String) { val hash = password.md5() // Tun Sie das niemals! database.saveHash(hash)}Richtiger Ansatz (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}Wichtig: Verwenden Sie bcrypt, scrypt oder Argon2. Verwenden Sie niemals MD5 oder SHA-1 zur Speicherung von Passwörtern.
4. Datenleck vertraulicher Daten durch Logs
Entwickler protokollieren oft sensible Daten, ohne zu prüfen, was in die Ausgabe gelangt.
Problematischer Code:
logger.info("Benutzer $userId mit Token authentifiziert: $token")Sichere Version:
logger.info("Benutzer $userId erfolgreich authentifiziert")// Oder verwenden Sie Maskierung:fun maskToken(token: String): String = token.take(4) + "****" + token.takeLast(4)Regel: Protokollieren Sie niemals Passwörter, Tokens, Kreditkartennummern oder personenbezogene Daten. Verwenden Sie Bibliotheken zur Maskierung (z. B. Logstash).
5. Unsichere Deserialisierung
Kotlin verwendet aktiv JSON-Serialisierung. Eine falsche Konfiguration kann zu RCE-Angriffen führen.
Verwundbarer Code (Jackson):
val mapper = ObjectMapper()val obj = mapper.readValue(userInput, Any::class.j