Kotlin应用安全:十大常见漏洞实战解析
Kotlin已稳居Android开发和服务器端应用最流行的语言之一。然而,与其他任何语言一样,Kotlin也无法避免漏洞。本文将解析开发者面临的最关键的十大安全问题,并展示如何在实践中避免它们。
1. SQL注入(SQL Injection)
尽管Kotlin常与ORM库配合使用,但直接编写SQL查询仍然是常见做法。
存在漏洞的代码:
fun getUser(id: String): User? { val query = "SELECT * FROM users WHERE id = '$id'" val result = connection.createStatement().executeQuery(query) // ...}安全版本(使用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() // ...}结论:切勿将用户输入拼接到SQL查询中。请使用参数化查询或ORM(Exposed、Hibernate)。
2. Web应用中的跨站脚本攻击(XSS)
在使用Ktor或Spring Boot开发服务器端应用时,经常忘记对输出进行转义。
存在漏洞的代码(Ktor):
get("/user/{name}") { val name = call.parameters["name"] ?: "访客" call.respondText("<h1>你好, $name!</h1>", ContentType.Text.Html)}安全版本:
import org.apache.commons.text.StringEscapeUtils
get("/user/{name}") { val name = call.parameters["name"] ?: "访客" val safeName = StringEscapeUtils.escapeHtml4(name) call.respondText("<h1>你好, $safeName!</h1>", ContentType.Text.Html)}建议:在输出到HTML之前,始终对用户输入进行转义。使用支持自动转义的模板引擎(例如Kotlinx.html)。
3. 密码存储不安全
以明文或使用弱哈希存储密码是最常见的错误之一。
错误做法:
fun savePassword(password: String) { val hash = password.md5() // 永远不要这样做! database.saveHash(hash)}正确做法(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}重要:请使用bcrypt、scrypt或Argon2。切勿使用MD5或SHA-1存储密码。
4. 通过日志泄露敏感数据
开发者经常记录敏感数据,而不检查输出内容。
有问题的代码:
logger.info("用户 $userId 使用令牌 $token 已授权")安全版本:
logger.info("用户 $userId 已成功授权")// 或者使用掩码处理:fun maskToken(token: String): String = token.take(4) + "****" + token.takeLast(4)规则:切勿记录密码、令牌、信用卡号或个人数据。使用掩码处理库(例如Logstash)。
5. 不安全的反序列化
Kotlin广泛使用JSON序列化。配置不当可能导致RCE攻击。
存在漏洞的代码(Jackson):
val mapper = ObjectMapper()val obj = mapper.readValue(userInput, Any::class.j