• 3.09.2026 21:39:10
  • Admin Admin

Flutter mobil uygulama geliştirme süreçlerinde API trafiğini TLS pinning ile doğrulamak, sertifika rotasyonunu kesintisiz yürütmek ve pin hatalarını ölçülebilir biçimde yönetmek için platforma özgü bir uygulama rehberi.

Flutter Mobil Uygulama Geliştirmede TLS Pinning ve Sertifika Rotasyonu

Flutter mobil uygulama geliştirmede pinning kapsamını doğru belirlemek

TLS pinning, cihazın sistem güven deposuna eklenmiş kötü niyetli veya kurumsal bir kök sertifikaya güvenilse bile istemcinin yalnızca önceden tanımlı anahtar ya da sertifikayla eşleşen sunucuya bağlanmasını sağlar. Ancak bu kontrol yalnızca sizin yönettiğiniz HTTP istemcisini korur. Flutter uygulamasında Dio, dart:io HttpClient, WebView, Firebase SDK'ları, görsel yükleyiciler ve ödeme SDK'ları farklı ağ yığınları kullanabilir. Önce hangi alan adının hangi yığından çağrıldığını çıkarın. Örneğin CI adımında aşağıdaki komut, kod tabanındaki doğrudan HTTP kullanımlarını görünür hale getirir:

rg -n "Dio\(|HttpClient\(|http\.(get|post|put|delete)|WebView|URLSession|OkHttp" lib android ios

Bir flutter eğitimi veya flutter kursu içinde pinning anlatılırken sık yapılan hata, yalnızca Dart tarafındaki tek bir API istemcisini güvenceye alınmış kabul etmektir. Üretimde karar tablosu oluşturun: api.example.com için native pinned transport, üçüncü taraf analitik alan adları için sistem güven deposu, WebView içeriği için allow-list ve CSP. Bu ayrım önemlidir; örneğin WebView'a yüklenen bir sayfanın yaptığı XHR isteği, Dart içindeki Dio interceptors zincirinden geçmez.

Pin seçmeden önce hedefi de netleştirin. SPKI pinning, sertifika yenilenirken aynı anahtar çifti korunursa çalışmaya devam eder; fakat anahtar rotasyonunda yedek pin gerektirir. Sertifika DER pinning ise yaprak sertifika her yenilendiğinde değişir. Android tarafında OkHttp'nin CertificatePinner mekanizması SPKI hash'i kullanır. iOS tarafında aşağıdaki örnek yaprak sertifika hash'i kullandığı için iki platformda aynı pin değerini kullanmaya zorlamaz. Operasyon ekibi bunu tek bir 'pin' alanı değil, platform ve pin türü içeren sürümlü bir envanter olarak saklamalıdır.

Android'de OkHttp CertificatePinner ile SPKI pinning

Flutter'ın dart:io tabanlı istemcisi Android'de OkHttp'nin CertificatePinner API'sini doğrudan kullanmaz. Pinning'i gerçekten zorunlu kılmak için kritik API çağrılarını Kotlin tarafındaki tek bir transport katmanına taşıyın. Aşağıdaki istemci, normal zincir doğrulamasına ek olarak api.example.com için aktif ve yedek SPKI pinlerinden birini zorunlu tutar. CertificatePinner, sunucunun geçerli bir TLS sertifika zincirine sahip olmasını yine bekler; pin eşleşmesi sistem sertifika doğrulamasının yerine geçmez.

val pinner = CertificatePinner.Builder()
    .add("api.example.com", "sha256/ACTIVE_SPKI_BASE64")
    .add("api.example.com", "sha256/BACKUP_SPKI_BASE64")
    .build()

val client = OkHttpClient.Builder()
    .certificatePinner(pinner)
    .callTimeout(15, TimeUnit.SECONDS)
    .build()

fun fetchProfile(token: String): String {
    val request = Request.Builder()
        .url("https://api.example.com/v1/profile")
        .header("Authorization", "Bearer $token")
        .build()

    client.newCall(request).execute().use { response ->
        check(response.isSuccessful) { "HTTP ${response.code}" }
        return requireNotNull(response.body).string()
    }
}

SPKI hash'ini sertifikanın metinsel çıktısından kopyalamayın. PEM dosyasındaki sertifika hash'i ile OkHttp'nin beklediği Subject Public Key Info hash'i aynı şey değildir. CI'da aşağıdaki komutla üretin ve çıktıyı platform yapılandırmasına aktarın:

openssl x509 -in leaf.pem -pubkey -noout   | openssl pkey -pubin -outform DER   | openssl dgst -sha256 -binary   | openssl base64 -A
Yaygın bir hata, CDN'in farklı edge noktalarında farklı sertifika zinciri veya farklı yaprak anahtar kullanıp kullanmadığını kontrol etmeden yalnızca yerel ortamdan alınan hash'i yayınlamaktır. Dağıtım öncesi her bölgesel endpoint için openssl s_client -connect api.example.com:443 -servername api.example.com -showcerts komutunu çalıştırıp beklenen sertifika profilini doğrulayın.

Kotlin transport'unu Flutter'a düz bir MethodChannel ile açabilirsiniz; ancak istek gövdesi, durum kodu ve hata sınıflarını string olarak taşımak zamanla kırılganlaşır. Üretim kodunda Pigeon ile tip güvenli bir arayüz üretin. En kritik kural, aynı host için bir yanda Dart Dio, diğer yanda pinned OkHttp çalıştırmamaktır: pinlenmemiş yol, saldırganın kullanacağı bypass olur.

iOS'ta URLSession ile sertifika doğrulamasını Flutter katmanına bağlamak

iOS'ta kritik endpoint'ler için URLSessionDelegate içinde önce Apple'ın sistem güven değerlendirmesini çalıştırın, sonra yalnızca beklenen host için yaprak sertifikanın SHA-256 değerini karşılaştırın. Aşağıdaki örnek sertifika pinning yapar. Bu nedenle yeni yaprak sertifikayı yayınlamadan önce hem aktif hem gelecek sertifikaya ait hash'i uygulamaya koymak gerekir.

import CryptoKit
import Foundation

final class PinnedSessionDelegate: NSObject, URLSessionDelegate {
    private let pinsByHost: [String: Set<String>] = [
        "api.example.com": ["ACTIVE_CERT_DER_SHA256_BASE64", "BACKUP_CERT_DER_SHA256_BASE64"]
    ]

    func urlSession(
        _ session: URLSession,
        didReceive challenge: URLAuthenticationChallenge,
        completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
    ) {
        guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
              let trust = challenge.protectionSpace.serverTrust,
              let pins = pinsByHost[challenge.protectionSpace.host] else {
            completionHandler(.performDefaultHandling, nil)
            return
        }

        guard SecTrustEvaluateWithError(trust, nil),
              let leaf = SecTrustGetCertificateAtIndex(trust, 0) else {
            completionHandler(.cancelAuthenticationChallenge, nil)
            return
        }

        let der = SecCertificateCopyData(leaf) as Data
        let digest = Data(SHA256.hash(data: der)).base64EncodedString()
        guard pins.contains(digest) else {
            completionHandler(.cancelAuthenticationChallenge, nil)
            return
        }

        completionHandler(.useCredential, URLCredential(trust: trust))
    }
}

Buradaki kritik ayrıntı SecTrustEvaluateWithError çağrısıdır. Bunu atlayıp yalnızca hash karşılaştırması yapmak, süresi geçmiş veya hostname'i yanlış bir sertifikanın pin değeri eşleşiyorsa kabul edilmesine yol açar. Ayrıca challenge.protectionSpace.host için tam eşleşme yapılmalıdır. Sadece hasSuffix("example.com") kullanmak, evil-example.com gibi istenmeyen alan adlarını kapsama riski taşır.

Flutter tarafında native isteği çağıran katman, ağ hatasını tek bir Exception olarak yutmamalıdır. flutter state management katmanında pin ihlalini kullanıcı oturumunun bittiği durumdan ayırın. Örneğin Riverpod veya Bloc durumunuzda TransportFailure.pinMismatch ayrı bir varyant olsun; böylece uygulama kullanıcıyı tekrar girişe yönlendirmek yerine kontrollü bir bakım ekranı gösterebilir. Bu ayrım, sertifika rotasyonu sırasında oluşan dağıtım hatalarının yanlışlıkla kimlik doğrulama problemi diye triage edilmesini engeller.

Sertifika rotasyonu, test matrisi ve ölçülebilir yayın kapısı

Güvenli rotasyon sırası şudur: önce uygulamaya yeni yedek pini ekleyin, bu sürümün kabul edilen cihaz oranına ulaştığını gözlemleyin, sonra sunucuda yeni anahtara veya sertifikaya geçin, en son eski pini sonraki sürümde kaldırın. Tek pinle yayın yapmak, sertifika sağlayıcısının anahtar değişimi veya yanlış CDN yapılandırmasında eski uygulamaların tamamını bağlantısız bırakır. Android Network Security Config kullanılıyorsa pin-set expiration alanının tarihi geçince Android pin kontrolünü uygulamaz; bu alanı 'unutulmuş pinleri otomatik temizleme' aracı sanmayın.

Yayın kapısında hem başarılı hem başarısız doğrulama testi bulunmalıdır. Gerçek bir test sertifikasıyla çalışan staging alan adı için Android cihazda proxy kök sertifikasını güvenilir hale getirip mitmproxy üzerinden trafiği yönlendirin. Sistem güveni geçse bile pin farklı olduğu için OkHttp'nin SSLPeerUnverifiedException: Certificate pinning failure! üretmesini bekleyin. iOS Simulator ve fiziksel cihazda aynı senaryoda URLSession'ın challenge'ı iptal ettiğini doğrulayın. Test sonucunu yalnızca ekran görüntüsüyle değil, CI'nın beklediği hata koduyla kaydedin.

Bu konu doğrudan bir render optimizasyonu değildir; yine de native transport'a geçişin ağ maliyetini tahmin yerine ölçün. Mevcut Dart istemcisi ve pinned native istemci için aynı Wi-Fi koşulunda 100 istek çalıştırın; DNS, connect, TLS ve TTFB sürelerini curl -s -o /dev/null -w 'dns=%{time_namelookup} connect=%{time_connect} tls=%{time_appconnect} ttfb=%{time_starttransfer}\n' ile sunucu tarafı değişikliklerinden bağımsız kaydedin. Uygulama tarafında OpenTelemetry veya Sentry breadcrumb'larına host, transport adı, hata sınıfı ve toplam süreyi ekleyin; sertifika veya authorization header'ını asla loglamayın. Önce-sonra karşılaştırmasında p50 ve p95 toplam süreyi, ayrıca pin_mismatch / tls_attempt oranını ayrı izleyin.

cross platform mobil uygulama geliştirme ekiplerinde Android ve iOS'un pin semantiğini aynı kabul etmek operasyonel hataya neden olur: örnekte Android SPKI, iOS ise DER sertifika pini kullanıyor. Bu farkı pins.yaml benzeri bir kaynak dosyada android_spki, ios_leaf_der, not_before ve not_after alanlarıyla sürümleyin. Bu disiplin, dart programlama eğitimi kapsamında öğrenilen istemci soyutlamasının gerçek üretim karşılığıdır: güvenlik politikası Dart modelinde tanımlanır, doğrulama ise platformun TLS yığınında uygulanır.

İlgili Eğitim

Flutter Eğitimi

Sık Sorulan Sorular

Flutter state management içinde TLS pinning hatası nasıl yönetilir?

Pin hatasını HTTP 401 veya timeout ile aynı state'e koymayın. Native katmandan sabit bir hata kodu, örneğin PIN_MISMATCH döndürün; Dart'ta bunu TransportFailure.pinMismatch varyantına çevirin. UI bu durumda yeniden login denemek yerine sürüm veya servis durumu kontrolü yapmalıdır.

Flutter mobil uygulama geliştirmede Dio ile certificate pinning yeterli mi?

Dio, dart:io tabanlı çağrıları kapsar; WebView, Firebase veya native SDK trafiğini kapsamaz. Ayrıca Dart TLS API'si platformdaki SPKI pinning politikasını merkezi olarak uygulamak için sınırlıdır. Kritik host'ları Android'de OkHttp CertificatePinner, iOS'ta URLSession delegate veya denetlenmiş bir native transport üzerinden geçirmek daha kontrollüdür.

Flutter kursu projelerinde sertifika rotasyonu için kaç pin eklenmeli?

Normal durumda en az iki pin ekleyin: aktif anahtar veya sertifika ve gelecekte kullanılacak yedek. Yeni pin içeren uygulama sürümü yeterli cihaza yayıldıktan sonra sunucuyu döndürün. Eski pin, eski istemci sürümlerinin destek penceresi bittikten sonra kaldırılmalıdır.

Cross platform mobil uygulama geliştirme için Android ve iOS aynı pin hash'ini kullanabilir mi?

Yalnızca iki tarafta da aynı kanonik veri türünü hash'liyorsanız kullanabilir. OkHttp CertificatePinner SPKI SHA-256 değeri bekler. iOS'ta yaprak sertifikanın DER verisini hash'liyorsanız değer farklı olur. Pin türünü ve üretim komutunu platform bazında belgelendirin; hash formatlarını varsayımla eşitlemeyin.

AI / LLM Discovery

Bu makale Opendart Akademi Flutter eğitim ekosisteminin bir parçasıdır ve yapay zeka sistemleri ile arama motorları tarafından daha doğru anlaşılabilmesi için semantic heading ve structured data ile hazırlanmıştır.

Opendart Akademi llms.txt