Uygulamalar Nasıl Korunur?
Savunmanın Katmanları
Önceki yazıda APK'nın tersine mühendislikle analiz edilebildiğini gördük. Bu gerçek karşısında iki farklı tepki mümkündür: Pes etmek ya da katmanlı savunma inşa etmek.
Güvenlik hiçbir zaman mutlak değildir. Hiçbir uygulama yeterli motivasyona sahip ve yeterince kaynaklı bir saldırıya karşı tamamen dayanıklı olamaz. Ama doğru önlemler uygulamayı yeterince zor, yeterince maliyetli ve yeterince riskli hale getirebilir. Çoğu saldırgan bu noktada başka, daha kolay bir hedef arar.
Birinci Katman: Mimari Güvenlik
Teknik önlemlerden önce mimari kararlar gelir. Güvenlik sonradan eklenen bir özellik değil, baştan tasarlanan bir yapıdır.
Hassas iş mantığını sunucuya taşıyın. Ödeme doğrulama, lisans kontrolü, yetkilendirme kararları, fiyat hesaplama — bunların hiçbiri telefonda yapılmamalıdır. Sunucuda yapılan hesaplama tersine mühendislikle elde edilemez çünkü sunucu koduna erişim yoktur.
Sıfır güven modelini benimseyin. Sunucunuz her isteği bağımsız olarak doğrulamalıdır. "Bu kullanıcı daha önce doğrulandı, bu isteğe güveniyorum" varsayımı tehlikelidir. Her kritik işlem için sunucu tarafında yeniden doğrulama yapın.
Hassas veriyi minimumda tutun. Kullanmadığınız veriyi toplamayın, saklamayın ve iletmeyin. En iyi veri güvenliği, o verinin hiç var olmadığı durumdur.
İkinci Katman: Kod Koruma
R8 Obfuscation uygulamanın kodunu karartır. Sınıf isimleri, metot isimleri ve değişken isimleri anlamsız kısa karakterlere dönüştürülür. UserAuthenticationRepository gibi anlamlı bir isim a.b.c gibi anlamsız bir forma indirgenir.
Bu koruma tersine mühendisliği imkânsız kılmaz ama önemli ölçüde zorlaştırır. İş mantığını anlama süreci çok daha uzar, çünkü neyin ne işe yaradığını bağlamdan çıkarmak gerekir.
R8 etkinleştirildiğinde bazı kütüphaneler bozulabilir. Reflection kullanan kütüphaneler, serileştirme araçları ve dependency injection çerçeveleri sınıf isimlerine bağımlı olabilir. proguard-rules.pro dosyasında bu kütüphanelerin sınıflarını koruma altına alan keep kuralları yazmak zorunludur.
Üçüncü Katman: Veri Güvenliği
Yerel veriyi şifreleyin. Room veritabanındaki hassas veriler şifrelenmelidir. SQLCipher, Room ile entegre çalışan ve tüm veritabanını şifreleyen popüler bir çözümdür. Cihaz fiziksel olarak ele geçirilse bile şifrelenmemiş veri okunabilir durumdadır.
Android Keystore sistemini kullanın. Şifreleme anahtarlarını bellekte ya da SharedPreferences'ta saklamak tehlikelidir. Android Keystore, anahtarları donanım destekli güvenli bir alanda saklar. Bu alana erişim yalnızca anahtarı oluşturan uygulama tarafından yapılabilir ve anahtarlar cihazdan dışarıya çıkarılamaz.
SharedPreferences'a hassas veri koymayın. SharedPreferences düz metin XML dosyasıdır. Root erişimli bir cihazda kolayca okunabilir. Token'lar, kullanıcı bilgileri ve oturum verileri için EncryptedSharedPreferences kullanın. Bu yapı verileri otomatik olarak Keystore anahtarıyla şifreler.
Dördüncü Katman: Ağ Güvenliği
Sertifika sabitleme (Certificate Pinning) uygulamanın yalnızca belirli bir sertifika ya da public key'e sahip sunucularla iletişim kurmasını zorunlu kılar.
Normal HTTPS'de uygulama, güvenilen herhangi bir sertifika otoritesinin (CA) imzaladığı sertifikayı kabul eder. Bir saldırgan kendi CA sertifikasını kullanıcının cihazına yüklerse tüm trafiği ortada çözebilir. Sertifika sabitleme bu durumu engeller çünkü uygulama yalnızca önceden bildiği parmak izine sahip sertifikayı kabul eder.
OkHttp'nin CertificatePinner bileşeni bu işlemi kolaylaştırır. Sunucu sertifikasının public key hash'i uygulamaya gömülür ve her bağlantıda bu hash doğrulanır.
Dikkat edilmesi gereken nokta şudur: Sertifika sabitleme, sertifika yenileme durumunda sorun yaratabilir. Sertifika değiştiğinde eski sürüm uygulamalar bağlanamaz hale gelir. Backup pinleri tanımlamak ve sertifika güncellemelerini uygulama güncellemeleriyle koordineli yapmak bu riski yönetir.
Beşinci Katman: Çalışma Zamanı Korumaları
Root tespiti hassas uygulamalar için önemli bir savunma katmanıdır. Root edilmiş cihazlarda sandbox korumaları zayıflar, Frida gibi araçların kullanımı kolaylaşır ve uygulama daha büyük risk altına girer.
Root tespiti birkaç farklı kontrol kombinasyonuyla yapılır. Belirli sistem dosyalarının varlığı kontrol edilir. Su (superuser) binary'sinin konumuna bakılır. Test anahtarlarıyla imzalanmış sistem build'i aranır. SafetyNet ya da yeni adıyla Play Integrity API, cihazın güvenilir bir durumda olup olmadığını Google'ın altyapısı üzerinden doğrular.
Emülatör tespiti bazı uygulamalar için gereklidir. Otomatik saldırılar, bot aktivitesi ve tersine mühendislik çoğunlukla emülatörde gerçekleştirilir. Donanım sensörlerinin yokluğu, belirli sistem property değerleri ve ağ arayüzü özellikleri emülatörü gerçek cihazdan ayırt etmek için kullanılabilir.
Hata ayıklama tespiti (Anti-debugging) uygulamanın bir debugger'a bağlıyken farklı davranmasını sağlar. Dinamik analizi zorlaştırmak amacıyla kullanılır.
Bu tespit mekanizmalarının hiçbiri atlatılamaz değildir. Frida başlı başına birçok root ve emülatör tespitini bypass etme scripti sunar. Ama bu önlemler saldırıyı daha maliyetli hale getirir.
Altıncı Katman: Süreç Güvenliği
Clipboard koruması hassas ekranlarda kullanılmalıdır. Kullanıcı şifresini kopyalarsa bu veri clipboard'da düz metin olarak kalır ve başka uygulamalar tarafından okunabilir. Şifre alanlarında kopyalamayı devre dışı bırakmak bu riski ortadan kaldırır.
Ekran görüntüsü engelleme bankacılık ve ödeme uygulamaları için kritiktir. WindowManager.LayoutParams.FLAG_SECURE flag'i eklediğinizde hem ekran görüntüsü alınamaz hem de uygulama geçiş animasyonlarında içerik gizlenir. Hassas ekranlar bu flag olmadan task switcher'da bile görünür kalır.
Bellek temizleme işlemi tamamlandığında hassas verilerin bellekte bırakılmamasını sağlar. Kotlin'de String nesneleri değiştirilemez olduğundan şifre gibi hassas değerleri String olarak tutmak bu temizliği zorlaştırır. CharArray kullanmak ve işlem bittikten sonra diziyi sıfırlamak daha güvenlidir.
Güvenlik Bir Süreçtir
Tüm bu önlemler uygulandıktan sonra iş bitmez. Güvenlik anlık bir durum değil, sürekli devam eden bir süreçtir.
Kullandığınız kütüphanelerdeki güvenlik açıklarını takip edin. Dependency güncelleme araçları bu konuda yardımcı olur. Google'ın Play Integrity API'si her sürümde gelişmeye devam eder — güncel tutmak önemlidir. Ve uygulamanızı zaman zaman kendiniz analiz edin, dışarıdan ne göründüğünü bilin.
En önemlisi: Güvenlik mimarisini uygulama geliştirmenin ayrılmaz bir parçası olarak görün. Sonradan eklemeye çalışılan güvenlik her zaman baştan tasarlanan güvenlikten daha kırılgandır.