Irbisa · Cheatsheet
Security, Privacy & Keychain
Data protection classes, ATS and TLS, certificate pinning, biometrics, jailbreak detection, secrets in the build, permissions, ATT and location
What is the Keychain on iOS, how is it protected, and what kinds of items can it hold?
Can you hide an API key in
Info.plistor an.xcconfigfile? Where should a secret the app relies on actually live?How do you add Face ID / Touch ID to an app with
LocalAuthentication?import LocalAuthentication // Info.plist needs NSFaceIDUsageDescription, or Face ID requests failfunc unlockWithBiometrics() async -> Bool { let context = LAContext() context.localizedFallbackTitle = "Enter Password"…How do runtime permissions work on iOS: what happens if
NSCameraUsageDescriptionis missing, and what can the app do after the user taps Don't Allow?import AVFoundationimport UIKit enum CameraAccess { case granted, denied, restricted } // Info.plist: NSCameraUsageDescription = "Scan the QR code on your parcel"…How does HTTPS protect a request: what does the TLS handshake agree on, and what does the app check in the server's certificate?
What are the Data Protection classes for files, which one does a file get by default, and when would you change it?
// A file that must be unreadable while the phone is lockedfunc saveStatement(_ pdf: Data, to url: URL) throws { try pdf.write(to: url, options: [.atomic, .completeFileProtection])} // On a directory: new files created inside inherit the class…Find the bug: users get signed out at random, usually when the app syncs in the background and the phone is locked.
func saveToken(_ token: Data) { SecItemAdd([kSecClass: kSecClassGenericPassword, kSecAttrService: "auth", kSecValueData: token, kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked] as CFDictionary, nil)}func readToken() -> String? { var result: CFTypeRef? let query = [kSecClass: kSecClassGenericPassword, kSecAttrService: "auth", kSecReturnData: true] as CFDictionary guard SecItemCopyMatching(query, &result) == errSecSuccess, let data = result as? Data else { return nil } return String(decoding: data, as: UTF8.self)}// Runs from a silent push and a BGAppRefreshTask, usually with the phone locked:func backgroundSync() async { guard let token = readToken() else { return session.logOut() } await api.sync(token: token)}An
httpsrequest fails with-1200and-9802in the log, yet the same URL loads in a browser. What does ATS demand that the server lacks, and how do you check?Find the bug: pinning works in the test, but a proxy with a user-installed CA can still read the app's traffic.
final class PinningDelegate: NSObject, URLSessionDelegate { let pinnedKeyHash: Data // SHA-256 of the server's public key init(pinnedKeyHash: Data) { self.pinnedKeyHash = pinnedKeyHash } func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping @Sendable (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { guard let trust = challenge.protectionSpace.serverTrust, SecTrustEvaluateWithError(trust, nil), let leaf = (SecTrustCopyCertificateChain(trust) as? [SecCertificate])?.first, let key = SecCertificateCopyKey(leaf), let raw = SecKeyCopyExternalRepresentation(key, nil) as Data?, Data(SHA256.hash(data: raw)) == pinnedKeyHash else { completionHandler(.performDefaultHandling, nil) // pin mismatch: use system trust return } completionHandler(.useCredential, URLCredential(trust: trust)) }}How do you hash, encrypt and authenticate data with CryptoKit, and where does the encryption key live?
import CryptoKit // Hash: a fingerprint for integrity checks, not for storing passwordslet digest = SHA256.hash(data: Data("report.pdf contents".utf8))let hex = digest.map { String(format: "%02x", $0) }.joined()…How does privacy work in
Loggerandos_log, and what must never reach the device log?import os let log = Logger(subsystem: "com.example.bank", category: "auth") func didSignIn(userID: Int, email: String, plan: String) { log.info("Signed in user \(userID)") // numbers: public by default…How do you keep sensitive screens out of the app-switcher snapshot and out of screen recordings on iOS?
import SwiftUI struct BankRoot: View { @Environment(\.scenePhase) private var phase var body: some View {…What is App Tracking Transparency, when may you show its prompt, and what happens to the IDFA and ad attribution when the user declines?
import AppTrackingTransparencyimport AdSupportimport UIKit // Info.plist: NSUserTrackingUsageDescription says what the user gets in return@MainActor…What is the difference between When In Use and Always location access, and what does turning off Precise Location change for your code?
import CoreLocation @MainActorfinal class LocationGate: NSObject, CLLocationManagerDelegate { private let manager = CLLocationManager()…This jailbreak check ships in a banking app. What does it catch, how is it bypassed, and what should the app do instead of
exit(0)?@MainActor func isJailbroken() -> Bool { let paths = ["/Applications/Cydia.app", "/bin/bash", "/usr/sbin/sshd", "/etc/apt"] if paths.contains(where: { FileManager.default.fileExists(atPath: $0) }) { return true } if UIApplication.shared.canOpenURL(URL(string: "cydia://")!) { return true } do { try "x".write(toFile: "/private/jb.txt", atomically: true, encoding: .utf8) return true // the sandbox should have refused this write } catch { return false }} // application(_:didFinishLaunchingWithOptions:)// if isJailbroken() { exit(0) }What is the Secure Enclave, and how do you create and use a key in it with CryptoKit?
import CryptoKitimport Security enum EnclaveError: Error { case unavailable } func makeDeviceKey() throws -> SecureEnclave.P256.Signing.PrivateKey {…What do
.userPresence,.biometryAnyand.biometryCurrentSetchange for a Keychain item, and what happens to it when the user enrolls a new face?import LocalAuthenticationimport Security func saveRefreshToken(_ token: Data) -> OSStatus { let access = SecAccessControlCreateWithFlags( nil, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, .biometryCurrentSet, nil)!…You pin the server's public key. How do you rotate that key without locking out users on old app versions?
<key>NSAppTransportSecurity</key><dict> <key>NSPinnedDomains</key> <dict> <key>api.example.com</key> <dict>…What are DeviceCheck and App Attest, and what does each one let your server verify?
import CryptoKitimport DeviceCheck enum AttestError: Error { case unsupported } // Once per install: create a key and let Apple vouch for it…How would you design the app lock for a banking app with a 6-digit PIN, Face ID and auto-lock after a minute in the background?