# iOS Network Security Advanced: Sıfırdan Zırhlı İletişim
Mobil uygulamanız ile sunucunuz arasındaki her byte, potansiyel bir saldırı yüzeyi. Man-in-the-Middle (MITM) saldırıları, certificate spoofing, request tampering ve traffic analysis — bunlar teorik tehditler değil, her gün gerçekleşen saldırılar. Bu rehberde, iOS uygulamanızın ağ katmanını askeri düzeyde koruma altına alacağız.
Uyarı: Bu rehberdeki teknikler savunma amaçlıdır. Güvenlik, katmanlı bir yaklaşım gerektirir; tek bir önlem yeterli değildir.
İçindekiler
- HTTPS ve TLS Temelleri
- Certificate Pinning
- Mutual TLS (mTLS)
- Request Signing
- Anti-Tampering
- Proxy Detection
- Network Security Tablosu
- ALTIN İPUCU
- Sonuç ve Öneriler
1. HTTPS ve TLS Temelleri
App Transport Security (ATS), iOS 9'dan beri HTTPS'i zorunlu kılar. Ama varsayılan TLS yeterli mi?
TLS Handshake Süreci
- Client Hello: Desteklenen cipher suite'ler gönderilir
- Server Hello: Cipher suite ve sertifika seçilir
- Certificate Verification: Sertifika zinciri doğrulanır
- Key Exchange: Simetrik anahtar oluşturulur
- Encrypted Communication: Veri şifreli akar
ATS Konfigürasyonu
swift
1// Info.plist - En sıkı ATS ayarları2// NSAppTransportSecurity:3// NSAllowsArbitraryLoads: false (VARSAYILAN - degistirmeyin!)4// NSExceptionDomains:5// api.example.com:6// NSExceptionMinimumTLSVersion: TLSv1.37// NSRequiresCertificateTransparency: true8// NSExceptionRequiresForwardSecrecy: true9 10// Programmatic kontrol11final class TLSConfiguration {12 static func createSecureSession() -> URLSession {13 let config = URLSessionConfiguration.default14 config.tlsMinimumSupportedProtocolVersion = .TLSv1315 config.urlCache = nil // Hassas veri cache'leme16 config.requestCachePolicy = .reloadIgnoringLocalCacheData17 18 return URLSession(19 configuration: config,20 delegate: SecurityDelegate.shared,21 delegateQueue: nil22 )23 }24}2. Certificate Pinning
Certificate Pinning, uygulamanızın sadece bildiği sertifikalara güvenmesini sağlar. Sistem trust store'u atlanarak MITM saldırıları önlenir.
Pinning Stratejileri
Strateji | Güvenlik | Esneklik | Bakım | Önerilen |
|---|---|---|---|---|
**Certificate Pinning** | En yüksek | En düşük | Sertifika yenilemede update | Finans uygulamaları |
**Public Key Pinning** | Yüksek | Orta | Key değişmezse update gerekmez | Genel kullanım |
**CA Pinning** | Orta | Yüksek | Minimal | Kurumsal |
**HPKP Header** | Orta | Orta | Server-side | Web uygulamaları |
Public Key Pinning Implementasyonu
swift
1// MARK: - Certificate Pinner2final class CertificatePinner: NSObject, URLSessionDelegate {3 // Pin'lenmis public key hash'leri (SHA256, base64)4 private let pinnedKeyHashes: Set<String> = [5 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Primary6 "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=", // Backup7 ]8 9 func urlSession(10 _ session: URLSession,11 didReceive challenge: URLAuthenticationChallenge,12 completionHandler: @escaping(URLSession.AuthChallengeDisposition, URLCredential?) -> Void13 ) {14 guard challenge.protectionSpace.authenticationMethod ==15 NSURLAuthenticationMethodServerTrust,16 let serverTrust = challenge.protectionSpace.serverTrust else {17 completionHandler(.cancelAuthenticationChallenge, nil)18 return19 }20 21 // Sertifika zincirini dogrula22 let policies = [SecPolicyCreateSSL(true, challenge.protectionSpace.host as CFString)]23 SecTrustSetPolicies(serverTrust, policies as CFArray)24 25 var error: CFError?26 guard SecTrustEvaluateWithError(serverTrust, &error) else {27 completionHandler(.cancelAuthenticationChallenge, nil)28 return29 }30 31 // Public key pin kontrolu32 let certificateCount = SecTrustGetCertificateCount(serverTrust)33 var pinFound = false34 35 for index in 0..<certificateCount {36 guard let certificate = SecTrustCopyCertificateChain(serverTrust)37 .map({ ($0 as! [SecCertificate])[index] }),38 let publicKey = SecCertificateCopyKey(certificate),39 let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, nil) as Data? else {40 continue41 }42 43 let keyHash = publicKeyData.sha256().base64EncodedString()44 if pinnedKeyHashes.contains(keyHash) {45 pinFound = true46 break47 }48 }49 50 if pinFound {51 completionHandler(.useCredential, URLCredential(trust: serverTrust))52 } else {53 // Pin eslesmedi - muhtemel MITM saldirisi!54 SecurityLogger.log(.pinningFailure, host: challenge.protectionSpace.host)55 completionHandler(.cancelAuthenticationChallenge, nil)56 }57 }58}59 60extension Data {61 func sha256() -> Data {62 var hash = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))63 withUnsafeBytes { buffer in64 _ = CC_SHA256(buffer.baseAddress, CC_LONG(count), &hash)65 }66 return Data(hash)67 }68}Easter Egg
Gizli bir bilgi buldun!
Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?
3. Mutual TLS (mTLS)
Normal TLS'de sadece sunucu kimliğini doğrular. mTLS'de hem sunucu hem istemci birbirini doğrular.
swift
1// MARK: - mTLS Client2final class MutualTLSClient: NSObject, URLSessionDelegate {3 private let clientIdentity: SecIdentity4 5 init(p12Data: Data, password: String) throws {6 let options: [String: Any] = [kSecImportExportPassphrase as String: password]7 var items: CFArray?8 let status = SecPKCS12Import(p12Data as CFData, options as CFDictionary, &items)9 10 guard status == errSecSuccess,11 let array = items as? [[String: Any]],12 let first = array.first,13 let identity = first[kSecImportItemIdentity as String] else {14 throw SecurityError.invalidClientCertificate15 }16 17 self.clientIdentity = identity as! SecIdentity18 }19 20 func urlSession(21 _ session: URLSession,22 didReceive challenge: URLAuthenticationChallenge,23 completionHandler: @escaping(URLSession.AuthChallengeDisposition, URLCredential?) -> Void24 ) {25 switch challenge.protectionSpace.authenticationMethod {26 case NSURLAuthenticationMethodClientCertificate:27 // Client sertifikasini sun28 let credential = URLCredential(29 identity: clientIdentity,30 certificates: nil,31 persistence: .forSession32 )33 completionHandler(.useCredential, credential)34 35 case NSURLAuthenticationMethodServerTrust:36 // Normal server trust + pinning37 guard let trust = challenge.protectionSpace.serverTrust else {38 completionHandler(.cancelAuthenticationChallenge, nil)39 return40 }41 completionHandler(.useCredential, URLCredential(trust: trust))42 43 default:44 completionHandler(.performDefaultHandling, nil)45 }46 }47}4. Request Signing
Her API isteğinin imzalanması, request tampering'i önler.
swift
1// MARK: - HMAC Request Signer2struct RequestSigner {3 private let secretKey: Data4 5 init(secretKey: Data) {6 self.secretKey = secretKey7 }8 9 func sign(_ request: inout URLRequest) {10 let timestamp = String(Int(Date().timeIntervalSince1970))11 let nonce = UUID().uuidString12 13 // Imzalanacak veri olustur14 let method = request.httpMethod ?? "GET"15 let path = request.url?.path ?? "/"16 let query = request.url?.query ?? ""17 let bodyHash = (request.httpBody ?? Data()).sha256().base64EncodedString()18 19 let signatureInput = [method, path, query, timestamp, nonce, bodyHash]20 .joined(separator: "\n")21 22 // HMAC-SHA256 imza23 let signature = HMAC<SHA256>.authenticationCode(24 for: Data(signatureInput.utf8),25 using: SymmetricKey(data: secretKey)26 )27 let signatureString = Data(signature).base64EncodedString()28 29 // Header'lara ekle30 request.setValue(timestamp, forHTTPHeaderField: "X-Timestamp")31 request.setValue(nonce, forHTTPHeaderField: "X-Nonce")32 request.setValue(signatureString, forHTTPHeaderField: "X-Signature")33 }34}5. Proxy Detection
MITM proxy (Charles, mitmproxy vb.) kullanımını tespit edin:
swift
1// MARK: - Proxy Detector2struct ProxyDetector {3 static var isProxyConfigured: Bool {4 guard let proxySettings = CFNetworkCopySystemProxySettings()?.takeRetainedValue()5 as? [String: Any] else {6 return false7 }8 9 // HTTP Proxy kontrol10 if let httpProxy = proxySettings["HTTPProxy"] as? String,11 !httpProxy.isEmpty {12 return true13 }14 15 // HTTPS Proxy kontrol16 if let httpsProxy = proxySettings["HTTPSProxy"] as? String,17 !httpsProxy.isEmpty {18 return true19 }20 21 return false22 }23 24 static func enforceNoProxy() {25 if isProxyConfigured {26 SecurityLogger.log(.proxyDetected)27 // Hassas islemleri engelle veya uyar28 }29 }30}6. Network Security Katmanları
Katman | Koruma | Saldırı Türü | Zorluk |
|---|---|---|---|
**TLS 1.3** | Transport şifreleme | Pasif dinleme | Kolay |
**Certificate Pinning** | MITM koruması | Sahte sertifika | Orta |
**mTLS** | Karşılıklı doğrulama | Yetkisiz istemci | Zor |
**Request Signing** | Tampering koruması | İstek değiştirme | Orta |
**Proxy Detection** | Analiz koruması | Traffic sniffing | Kolay |
**Response Validation** | Veri bütünlüğü | Response injection | Orta |
swift
1// MARK: - Remote Pin Rotation Manager2final class PinRotationManager {3 private let keychain = KeychainHelper.shared4 private let remotePinURL = URL(string: "https://api.example.com/.well-known/pins.json")!5 private let cacheKey = "certificate_pins_v1"6 7 func currentPins() -> Set<String> {8 // 1. Keychain'deki guncel pin'leri oku9 if let cached = keychain.getData(cacheKey),10 let pins = try? JSONDecoder().decode(PinConfig.self, from: cached),11 pins.expiresAt > Date() {12 return Set(pins.hashes)13 }14 // 2. Fallback: bundle'daki hardcoded pin'ler15 return Set(BundledPins.defaultHashes)16 }17 18 func refreshPins() async {19 guard let (data, _) = try? await URLSession.shared.data(from: remotePinURL),20 let config = try? JSONDecoder().decode(PinConfig.self, from: data) else { return }21 keychain.set(data, forKey: cacheKey)22 }23 24 struct PinConfig: Codable {25 let hashes: [String] // Primary + backup pin hash'leri26 let expiresAt: Date // Cache suresi27 let minAppVersion: String // Minimum desteklenen versiyon28 }29}ALTIN İPUCU
Bu yazının en değerli bilgisi
Bu ipucu, yazının en önemli çıkarımını içeriyor.
Okuyucu Ödülü
Tebrikler! Bu yazıyı sonuna kadar okuduğun için sana özel bir hediyem var:
Sonuç ve Öneriler
Network güvenliği, tek bir önlemle sağlanamaz. TLS ile başlayın, certificate pinning ekleyin, hassas endpoint'ler için request signing uygulayın ve proxy detection ile analiz koruması sağlayın. Güvenlik katmanlıdır; her katman bir saldırı vektörünü kapatır. Paranoyak olmayın ama hazırlıklı olun.

