iOS güvenliği, kullanıcı verilerini ve uygulama bütünlüğünü korumak için kritik öneme sahiptir. Bu kapsamlı rehberde, modern iOS güvenlik best practice'lerini inceleyeceğiz.
İçindekiler
- Guvenlik Katmanlari Tablosu
- Keychain Services
- Biometric Authentication
- SSL Pinning
- Jailbreak Detection
- Data Protection
- Security Checklist
- Sonuç
iOS Guvenlik Katmanlari Karsilastirma Tablosu
Guvenlik Katmani | Koruma Alani | Zorluk | Oncelik | Bypass Riski |
|---|---|---|---|---|
**Keychain** | Token, sifre, credential | Kolay | Kritik | Dusuk |
**Biometric Auth** | Kullanici dogrulama | Kolay | Yuksek | Dusuk |
**SSL Pinning** | Network trafigi | Orta | Kritik | Orta |
**Jailbreak Detection** | Cihaz butunlugu | Orta | Orta | Yuksek |
**Code Obfuscation** | Kaynak kod | Zor | Orta | Orta |
**Data Protection** | Dosya sifreleme | Kolay | Yuksek | Dusuk |
**Runtime Protection** | Debugger engelleme | Zor | Orta | Yuksek |
**Input Validation** | Enjeksiyon saldirilari | Kolay | Kritik | Dusuk |
**Screen Capture Prevention** | Ekran goruntuleme | Kolay | Dusuk | Yuksek |
Keychain Services
Hassas verileri güvenli şekilde saklamak için Keychain kullanımı:
swift
1import Security2 3class KeychainManager {4 enum KeychainError: Error {5 case duplicateEntry6 case unknown(OSStatus)7 case notFound8 case unexpectedData9 }10 11 // Save12 static func save(key: String, data: Data, biometricProtected: Bool = false) throws {13 var query: [String: Any] = [14 kSecClass as String: kSecClassGenericPassword,15 kSecAttrAccount as String: key,16 kSecValueData as String: data17 ]18 19 if biometricProtected {20 let access = SecAccessControlCreateWithFlags(21 nil,22 kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,23 .biometryCurrentSet,24 nil25 )26 query[kSecAttrAccessControl as String] = access27 } else {28 query[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly29 }30 31 let status = SecItemAdd(query as CFDictionary, nil)32 33 if status == errSecDuplicateItem {34 // Update existing35 let updateQuery = [kSecValueData as String: data]36 SecItemUpdate(query as CFDictionary, updateQuery as CFDictionary)37 } else if status != errSecSuccess {38 throw KeychainError.unknown(status)39 }40 }41 42 // Read43 static func read(key: String) throws -> Data {44 let query: [String: Any] = [45 kSecClass as String: kSecClassGenericPassword,46 kSecAttrAccount as String: key,47 kSecReturnData as String: true,48 kSecMatchLimit as String: kSecMatchLimitOne49 ]50 51 var result: AnyObject?52 let status = SecItemCopyMatching(query as CFDictionary, &result)53 54 guard status == errSecSuccess else {55 throw KeychainError.notFound56 }57 58 guard let data = result as? Data else {59 throw KeychainError.unexpectedData60 }61 62 return data63 }64 65 // Delete66 static func delete(key: String) {67 let query: [String: Any] = [68 kSecClass as String: kSecClassGenericPassword,69 kSecAttrAccount as String: key70 ]71 SecItemDelete(query as CFDictionary)72 }73}74 75// Usage76struct Credentials: Codable {77 let accessToken: String78 let refreshToken: String79 let expiresAt: Date80}81 82class SecureStorage {83 func saveCredentials(_ credentials: Credentials) throws {84 let data = try JSONEncoder().encode(credentials)85 try KeychainManager.save(key: "user_credentials", data: data, biometricProtected: true)86 }87 88 func loadCredentials() throws -> Credentials {89 let data = try KeychainManager.read(key: "user_credentials")90 return try JSONDecoder().decode(Credentials.self, from: data)91 }92}Biometric Authentication
Face ID ve Touch ID entegrasyonu:
swift
1import LocalAuthentication2 3class BiometricAuthManager {4 enum BiometricType {5 case none6 case touchID7 case faceID8 }9 10 var biometricType: BiometricType {11 let context = LAContext()12 var error: NSError?13 14 guard context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) else {15 return .none16 }17 18 switch context.biometryType {19 case .faceID: return .faceID20 case .touchID: return .touchID21 default: return .none22 }23 }24 25 func authenticate(reason: String) async throws -> Bool {26 let context = LAContext()27 context.localizedCancelTitle = "İptal"28 context.localizedFallbackTitle = "Şifre Kullan"29 30 var error: NSError?31 guard context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) else {32 throw error ?? NSError(domain: "BiometricAuth", code: -1)33 }34 35 return try await context.evaluatePolicy(36 .deviceOwnerAuthenticationWithBiometrics,37 localizedReason: reason38 )39 }40}41 42// SwiftUI Integration43struct SecureView: View {44 @State private var isAuthenticated = false45 @State private var showError = false46 private let biometricAuth = BiometricAuthManager()47 48 var body: some View {49 Group {50 if isAuthenticated {51 ProtectedContentView()52 } else {53 AuthenticationPromptView {54 await authenticate()55 }56 }57 }58 .alert("Doğrulama Başarısız", isPresented: $showError) {59 Button("Tamam", role: .cancel) {}60 }61 }62 63 private func authenticate() async {64 do {65 isAuthenticated = try await biometricAuth.authenticate(66 reason: "Güvenli içeriğe erişmek için doğrulayın"67 )68 } catch {69 showError = true70 }71 }72}SSL Pinning
Man-in-the-middle saldırılarına karşı koruma:
swift
1import CryptoKit2 3class SSLPinningManager: NSObject, URLSessionDelegate {4 // Public key hash'leri (base64)5 private let pinnedHashes = [6 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // Primary7 "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=" // Backup8 ]9 10 func urlSession(11 _ session: URLSession,12 didReceive challenge: URLAuthenticationChallenge,13 completionHandler: @escaping(URLSession.AuthChallengeDisposition, URLCredential?) -> Void14 ) {15 guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,16 let serverTrust = challenge.protectionSpace.serverTrust else {17 completionHandler(.cancelAuthenticationChallenge, nil)18 return19 }20 21 // Sertifika zincirini doğrula22 var error: CFError?23 let isValid = SecTrustEvaluateWithError(serverTrust, &error)24 25 guard isValid else {26 completionHandler(.cancelAuthenticationChallenge, nil)27 return28 }29 30 // Public key pinning31 guard let certificate = SecTrustGetCertificateAtIndex(serverTrust, 0) else {32 completionHandler(.cancelAuthenticationChallenge, nil)33 return34 }35 36 let publicKey = SecCertificateCopyKey(certificate)37 let publicKeyData = SecKeyCopyExternalRepresentation(publicKey!, nil)! as Data38 let hash = SHA256.hash(data: publicKeyData)39 let hashString = Data(hash).base64EncodedString()40 41 if pinnedHashes.contains(hashString) {42 completionHandler(.useCredential, URLCredential(trust: serverTrust))43 } else {44 completionHandler(.cancelAuthenticationChallenge, nil)45 }46 }47}48 49// Alamofire ile SSL Pinning50import Alamofire51 52class SecureNetworkManager {53 static let shared = SecureNetworkManager()54 55 private let session: Session56 57 private init() {58 let evaluators: [String: ServerTrustEvaluating] = [59 "api.myapp.com": PublicKeysTrustEvaluator()60 ]61 62 let manager = ServerTrustManager(evaluators: evaluators)63 session = Session(serverTrustManager: manager)64 }65 66 func request<T: Decodable>(_ endpoint: String) async throws -> T {67 return try await session68 .request("https://api.myapp.com" + endpoint)69 .serializingDecodable(T.self)70 .value71 }72}Jailbreak Detection
swift
1class JailbreakDetector {2 static func isJailbroken() -> Bool {3 #if targetEnvironment(simulator)4 return false5 #else6 7 // 1. Suspicious files check8 let suspiciousFiles = [9 "/Applications/Cydia.app",10 "/Library/MobileSubstrate/MobileSubstrate.dylib",11 "/bin/bash",12 "/usr/sbin/sshd",13 "/etc/apt",14 "/private/var/lib/apt/"15 ]16 17 for path in suspiciousFiles {18 if FileManager.default.fileExists(atPath: path) {19 return true20 }21 }22 23 // 2. Write test24 let testPath = "/private/jailbreak_test.txt"25 do {26 try "test".write(toFile: testPath, atomically: true, encoding: .utf8)27 try FileManager.default.removeItem(atPath: testPath)28 return true29 } catch {30 // Expected on non-jailbroken devices31 }32 33 // 3. URL scheme check34 if let url = URL(string: "cydia://package/com.example.package"),35 UIApplication.shared.canOpenURL(url) {36 return true37 }38 39 // 4. Dylib injection check40 let count = _dyld_image_count()41 for i in 0..<count {42 if let name = _dyld_get_image_name(i) {43 let imageName = String(cString: name)44 if imageName.contains("MobileSubstrate") ||45 imageName.contains("Substrate") ||46 imageName.contains("cycript") {47 return true48 }49 }50 }51 52 return false53 #endif54 }55}Data Protection
swift
1// File protection levels2func saveSecureFile(data: Data, filename: String) throws {3 let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]4 let fileURL = documentsURL.appendingPathComponent(filename)5 6 try data.write(to: fileURL, options: .completeFileProtection)7 8 // Verify protection9 let attributes = try FileManager.default.attributesOfItem(atPath: fileURL.path)10 let protection = attributes[.protectionKey] as? FileProtectionType11 assert(protection == .complete)12}Security Checklist
- Keychain için hassas veriler
- Biometric authentication
- SSL/TLS pinning
- Jailbreak detection
- File protection
- Input validation
- Code obfuscation
- Debug detection
- Screen capture prevention
Sonuç
iOS güvenliği çok katmanlı bir yaklaşım gerektirir. Keychain, biometric auth, SSL pinning ve jailbreak detection gibi teknikleri kombine ederek uygulamanızı güvenli hale getirebilirsiniz.
Easter Egg
Gizli bir bilgi buldun!
Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?
Okuyucu Ödülü
Tebrikler! Bu yazıyı sonuna kadar okuduğun için sana özel bir hediyem var:
ALTIN İPUCU
Bu yazının en değerli bilgisi
Bu ipucu, yazının en önemli çıkarımını içeriyor.

