Piyasada bir 'otomasyon' çılgınlığı gidiyor, sormayın gitsin. Herkes bayılıyor o süslü dashboard’lara, renklendirilmiş PDF raporlarına. CI/CD pipeline’ına bir tane MobSF ya da benzeri bir araç entegre ettin, static analysis’den (SAST) 'geçti' ibaresini gördün ve tamam dedin; 'Uygulama hazır, yarın yayına alıyoruz.' Gerçekten mi? Prod ortamında bu araçlara güvenerek uygulama çıkarmak, fırtınalı denize kağıttan gemiyle açılmakla aynı şey.
Bakın, bu araçlar kötü değil. Ama sadece başlangıç seviyesindeki 'low-hanging fruit' dediğimiz, dalda sarkan en düşük meyveleri toplarlar. Gerçek bir Red Teamer uygulamanıza dadandığında, o scanner’ın ruhu bile duymaz. Gelin bugün, mobil güvenliğin o cicili bicili sunumlarından çıkıp, mutfakta işlerin nasıl yürüdüğüne bakalım.
SSL Pinning: Güvendiğin Dağlara Frida Yağması
Çoğu developer dostum, ağ trafiğini şifrelemek için SSL Pinning yapınca işin bittiğini sanıyor. 'Araya kimse giremez, trafiği göremez' diyorlar. Eskidendi o. Bugün Frida diye bir gerçek var. Runtime’da uygulamanın kalbine sızıp, senin o çok güvendiğin sertifika kontrol fonksiyonunu return true; diyerek geçmek sadece bir saniyemi alıyor.
Şöyle bir senaryo düşünelim; testCompany isimli firmamızın bir uygulaması var. Kodun içinde sertifikayı kontrol eden bir metot var. Tipik bir checkServerTrusted kontrolü.
Zararsızlaştırılmış (Defanged) Örnek Kod (Kotlin):
// Kötü bir SSL Pinning kontrolü örneği
class MyPinner : X509TrustManager {
override fun checkServerTrusted(chain: Array<out X509Certificate>?, authType: String?) {
val serverCert = chain?.get(0)
if (serverCert?.subjectDN?.name != "CN=api.example.com") {
throw CertificateException("Sertifika uyuşmuyor!")
}
}
// ... diğer metodlar
}
Bu kod kağıt üzerinde çalışıyor. Ama ben cihazı rootlayıp (veya rootlamadan bile!) Frida ile şu basit scripti çalıştırdığımda o kontrol puff diye uçuyor:
Zararsızlaştırılmış Frida Hook (Pseudo-code):
Java.perform(function () {
var MyPinner = Java.use("com.testCompany.app.security.MyPinner");
MyPinner.checkServerTrusted.implementation = function (chain, authType) {
console.log("[!] SSL Pinning bypass edildi. Devam ediyoruz...");
return; // Hata fırlatma, sessizce geç
};
});
Savunma Tavsiyesi: Sadece sertifika parmak izine bakmayın. Certificate Transparency loglarını kontrol edin ve mutlaka native katmanda (C++ / JNI) kontroller yapmaya çalışın. Java katmanı her zaman manipülasyona çok açıktır.
Root ve Jailbreak Tespiti: Kedi Fare Oyunu
Uygulamanın rootlu cihazda çalışmasını engellemek için if (File("/system/app/Superuser.apk").exists()) gibi kontroller yazan kaldı mı? Umarım kalmamıştır. Magisk ve türevleri, dosya sistemini öyle bir manipüle ediyor ki, o dosya orada olsa bile senin uygulaman onu göremiyor.
Root tespiti bir 'güvenlik önlemi' değil, bir 'geciktirme taktiğidir'. Eğer uygulamanın tüm iş mantığı (business logic) cihazın rootlu olup olmamasına bağlıysa, geçmiş olsun. Bir saldırgan için o isRooted() fonksiyonunun sonucunu değiştirmek çocuk oyuncağı.
Nasıl Hardening Yapılır?
- Tek bir noktada kontrol yapmayın. Kontrolleri uygulamanın farklı yerlerine dağıtın.
- Uygulama başlangıcında değil, kritik bir işlem (para transferi vs.) yapılacağı anda kontrol edin.
- 'Anti-tampering' kütüphaneleri kullanın ama onlara da %100 güvenmeyin.
Kodun İçine Saklanan Sırlar (Secrets)
En çok karşılaştığım durumlardan biri: API anahtarları, Firebase secret'ları ya da şifreleme anahtarlarının strings.xml veya BuildConfig içinde saklanması. 'Ama ben kodu obfuscate (karartma) ettim, kimse göremez' diyorsan, yanılıyorsun. Jadx-GUI diye bir araç var, kodu öyle bir açıyor ki her şey kabak gibi ortada.
Kritik Hata:
<!-- strings.xml içinde asla yapmayın -->
<string name="aws_secret_key">AKIA12345EXAMPLE67890</string>
Bunu gören bir saldırgan, senin AWS S3 bucket'ına sızıp tüm kullanıcı verilerini indirebilir. Mobil uygulama bir 'kasa' değil, bir 'vitrindir'. Vitrinde asla değerli mücevher (secret) bırakılmaz.
Peki Ne Yapalım? (Red Team Gözünden Tavsiyeler)
- Obfuscation (Karartma) Şart: ProGuard/R8 kullanmak yetmez. String'leri şifreleyen, kontrol akışını bozan (Control Flow Flattening) daha gelişmiş araçlara (DexGuard vb.) yatırım yapın.
- Logic Sunucuda Olmalı: Mobil uygulama sadece bir arayüzdür. Kritik kararlar (indirim uygulanacak mı, kullanıcı yetkili mi?) asla uygulama içinde verilmemelidir. API her zaman 'bu kullanıcı bunu yapmaya yetkili mi?' diye tekrar sormalıdır.
- Emulator ve Debugger Kontrolü: Uygulamanın bir debugger'a bağlı olup olmadığını kontrol eden
android.os.Debug.isDebuggerConnected()gibi basit ama etkili kontroller ekleyin. - Runtime Integrity: Uygulamanın kendi imzasını çalışma anında kontrol etmesini sağlayın. Ben uygulamanızı modifiye edip (repackaging) içine kendi kodumu gömdüğümde, uygulama bunu anlayıp kendini kapatmalı.
Son söz; o otomatik tarayıcılardan aldığınız tertemiz raporlar sizi rahatlatmasın. Siber güvenlik bir süreçtir, bir PDF dosyası değil. Bir gün kahveleri alıp uygulamayı beraber 'mıncıklayalım', bakalım o yeşil tikler ne kadar gerçekmiş.
Stay geek, stay secure!
