Безопасность Kotlin приложений: топ-10 уязвимостей для начинающих
Kotlin — современный язык программирования, который активно используется для создания Android-приложений, серверных решений и мультиплатформенных проектов. Однако даже с его строгой типизацией и безопасностью по умолчанию, разработчики-новички часто допускают ошибки, которые могут привести к серьёзным уязвимостям. В этой статье мы разберём топ-10 самых распространённых проблем безопасности в Kotlin-приложениях, покажем примеры опасного кода и дадим рекомендации по их устранению.
1. SQL-инъекции (SQL Injection)
Одна из самых старых и опасных уязвимостей. Если вы напрямую конкатенируете пользовательский ввод в SQL-запрос, злоумышленник может выполнить произвольные команды.
// ОПАСНО: конкатенация строк
val query = "SELECT * FROM users WHERE name = '$userInput'"
statement.executeQuery(query)
// БЕЗОПАСНО: использование параметризованных запросов
val query = "SELECT * FROM users WHERE name = ?"
val preparedStatement = connection.prepareStatement(query)
preparedStatement.setString(1, userInput)
preparedStatement.executeQuery()
2. Небезопасное хранение паролей
Никогда не храните пароли в открытом виде. Используйте bcrypt, Argon2 или PBKDF2. В Kotlin для этого можно использовать библиотеку spring-security-crypto или kotlinx-serialization с хешированием.
// ОПАСНО: хранение в plain text
data class User(val password: String)
// БЕЗОПАСНО: хеширование с солью
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
val encoder = BCryptPasswordEncoder()
val hashedPassword = encoder.encode(plainPassword)
3. Отсутствие проверки ввода (Input Validation)
Любые данные от пользователя должны проходить валидацию. Игнорирование этого правила ведёт к XSS, инъекциям и DoS-атакам.
// ОПАСНО: прямой вывод без экранирования
fun renderHtml(userInput: String): String {
return "<div>$userInput</div>"
}
// БЕЗОПАСНО: экранирование HTML
import org.owasp.encoder.Encode
fun renderSafeHtml(userInput: String): String {
return "<div>${Encode.forHtml(userInput)}</div>"
}
4. Уязвимости в сериализации данных
Kotlin использует kotlinx.serialization или Gson/Moshi. Неправильная настройка может привести к раскрытию чувствительных данных или удалённому выполнению кода.
// ОПАСНО: сериализация всех полей
@Serializable
data class User(
val name: String,
val passwordHash: String // утечка хеша!
)
// БЕЗОПАСНО: исключение чувствительных полей
@Serializable
data class SafeUser(
val name: String,
@Transient val passwordHash: String = ""
)
5. Небезопасное использование WebView (Android)
При разработке Android-приложений на Kotlin часто используют WebView. Если не отключить JavaScript или не настроить фильтрацию, возможна XSS-атака.
// ОПАСНО: включен JavaScript без фильтрации
webView.settings.javaScriptEnabled = true
webView.loadUrl("file:///android_asset/index.html")
// БЕЗОПАСНО: отключаем JavaScript для статического контента
webView.settings.javaScriptEnabled = false
// Или используем Content Security Policy
webView.loadDataWithBaseURL(null, content, "text/html", "UTF-8", null)
6. Неправильное управление сессиями
Хранение токенов аутентификации в SharedPreferences без шифрования — частая ошибка. Используйте EncryptedSharedPreferences или Android Keystore.
// ОПАСНО: открытое хранение токена
val prefs = context.getSharedPreferences("auth", Context.MODE_PRIVATE)
prefs.edit().putString("token", token).apply()
// БЕЗОПАСНО: шифрованное хранение
val encryptedPrefs = EncryptedSharedPreferences.create(
"secure_prefs",
MasterKey.DEFAULT_MASTER_KEY_ALIAS,
context,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
encryptedPrefs.edit().putString("token", token).apply()
7. Утечка информации через логирование
Разработчики часто логируют лишние данные: пароли, токены, номера карт. Это опасно в production.
// ОПАСНО: логирование чувствительных данных
log.info("User login: $username, password: $password")
// БЕЗОПАСНО: маскирование
log.info("User login: $username, password: [REDACTED]")
8. Небезопасное использование Coroutines
При работе с корутинами можно случайно запустить утечку ресурсов или выполнить неотменяемые операции, что приведёт к DoS.
// ОПАСНО: глобальный scope без отмены
GlobalScope.launch {
// бесконечная операция
}
// БЕЗОПАСНО: использование viewModelScope или lifecycleScope
viewModelScope.launch {
// операция автоматически отменяется при уничтожении ViewModel
}
9. Отсутствие проверки прав доступа (Android)
Не проверяйте разрешения только в одном месте. Злоумышленник может обойти проверку через Intent-фильтры.
// ОПАСНО: проверка только в Activity
if (checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
// доступ к камере
}
// БЕЗОПАСНО: проверка в каждом критическом методе
fun takePhoto() {
if (context.checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
requestPermission()
return
}
// безопасный доступ
}
10. Использование устаревших или небезопасных библиотек
Даже в Kotlin можно подключить библиотеку с известными уязвимостями. Регулярно обновляйте зависимости и используйте инструменты анализа (например, OWASP Dependency-Check).
// build.gradle.kts
dependencies {
// ОПАСНО: старая версия с CVE
implementation("com.squareup.okhttp3:okhttp:3.12.0")
// БЕЗОПАСНО