Claude Agent Skill · by Dpearson2699

Ios Security

Install Ios Security skill for Claude Code from dpearson2699/swift-ios-skills.

Install
Terminal · npx
$npx skills add https://github.com/microsoft/github-copilot-for-azure --skill azure-rbac
Works with Paperclip

How Ios Security fits into a Paperclip company.

Ios Security drops into any Paperclip agent that handles this kind of work. Assign it to a specialist inside a pre-configured PaperclipOrg company and the skill becomes available on every heartbeat — no prompt engineering, no tool wiring.

S
SaaS FactoryPaired

Pre-configured AI company — 18 agents, 18 skills, one-time purchase.

$27$59
Explore pack
Source file
SKILL.md495 lines
Expand
---name: ios-securitydescription: "Secure iOS apps with Keychain Services, CryptoKit encryption, biometric authentication (Face ID, Touch ID), Secure Enclave key storage, LAContext, App Transport Security (ATS), certificate pinning, data protection classes, and secure coding patterns. Use when implementing app security features, auditing privacy manifests, configuring App Transport Security, securing keychain access, adding biometric authentication, or encrypting sensitive data with CryptoKit."--- # iOS Security Guidance for handling sensitive data, authenticating users, encryptingcorrectly, and following Apple's security best practices on iOS. ## Contents - [Keychain Services](#keychain-services)- [Data Protection](#data-protection)- [CryptoKit](#cryptokit)- [Secure Enclave](#secure-enclave)- [Biometric Authentication](#biometric-authentication)- [App Transport Security (ATS)](#app-transport-security-ats)- [Certificate Pinning](#certificate-pinning)- [Secure Coding Patterns](#secure-coding-patterns)- [Privacy Manifests](#privacy-manifests)- [Common Mistakes](#common-mistakes)- [Review Checklist](#review-checklist)- [References](#references) ## Keychain Services The Keychain is the ONLY correct place to store sensitive data. Never storepasswords, tokens, API keys, or secrets in UserDefaults, files, or Core Data. ### Storing Credentials ```swiftfunc saveToKeychain(account: String, data: Data, service: String) throws {    let query: [String: Any] = [        kSecClass as String: kSecClassGenericPassword,        kSecAttrAccount as String: account,        kSecAttrService as String: service,        kSecValueData as String: data,        kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly    ]     let status = SecItemAdd(query as CFDictionary, nil)     if status == errSecDuplicateItem {        let updateQuery: [String: Any] = [            kSecClass as String: kSecClassGenericPassword,            kSecAttrAccount as String: account,            kSecAttrService as String: service        ]        let updates: [String: Any] = [kSecValueData as String: data]        let updateStatus = SecItemUpdate(updateQuery as CFDictionary, updates as CFDictionary)        guard updateStatus == errSecSuccess else {            throw KeychainError.updateFailed(updateStatus)        }    } else if status != errSecSuccess {        throw KeychainError.saveFailed(status)    }}``` ### Reading Credentials ```swiftfunc readFromKeychain(account: String, service: String) throws -> Data {    let query: [String: Any] = [        kSecClass as String: kSecClassGenericPassword,        kSecAttrAccount as String: account,        kSecAttrService as String: service,        kSecReturnData as String: true,        kSecMatchLimit as String: kSecMatchLimitOne    ]     var result: AnyObject?    let status = SecItemCopyMatching(query as CFDictionary, &result)     guard status == errSecSuccess, let data = result as? Data else {        throw KeychainError.readFailed(status)    }    return data}``` ### Deleting Credentials ```swiftfunc deleteFromKeychain(account: String, service: String) throws {    let query: [String: Any] = [        kSecClass as String: kSecClassGenericPassword,        kSecAttrAccount as String: account,        kSecAttrService as String: service    ]     let status = SecItemDelete(query as CFDictionary)    guard status == errSecSuccess || status == errSecItemNotFound else {        throw KeychainError.deleteFailed(status)    }}``` ### kSecAttrAccessible Values | Value | When Available | Device-Only | Use For ||---|---|---|---|| `kSecAttrAccessibleWhenUnlocked` | Device unlocked | No | General credentials || `kSecAttrAccessibleWhenUnlockedThisDeviceOnly` | Device unlocked | Yes | Sensitive credentials || `kSecAttrAccessibleAfterFirstUnlock` | After first unlock | No | Background-accessible tokens || `kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly` | After first unlock | Yes | Background tokens, no backup || `kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly` | Passcode set + unlocked | Yes | Highest security | Rules:- Use `ThisDeviceOnly` variants for sensitive data. Prevents backup/restore to other devices.- Use `AfterFirstUnlock` for tokens needed by background operations.- Use `WhenPasscodeSetThisDeviceOnly` for most sensitive data. Item is deleted if passcode is removed.- NEVER use `kSecAttrAccessibleAlways` (deprecated and insecure). ### Keychain Access Groups Share keychain items across apps from the same team: ```swiftlet query: [String: Any] = [    kSecClass as String: kSecClassGenericPassword,    kSecAttrAccount as String: "shared-token",    kSecAttrAccessGroup as String: "TEAMID.com.company.shared"]``` ### @AppStorage vs Keychain | Storage | Use For | Security ||---------|---------|----------|| `@AppStorage` / `UserDefaults` | Non-sensitive preferences (theme, onboarding state, feature flags) | Not encrypted at rest || Keychain | Passwords, tokens, API keys, secrets | Hardware-encrypted, access-controlled | **Rule:** If the data would be embarrassing or dangerous if exposed, it goes in Keychain. Everything else can use `@AppStorage`. ```swift// Non-sensitive preference -- @AppStorage is fine@AppStorage("hasCompletedOnboarding") private var hasOnboarded = false // Sensitive credential -- MUST use Keychain// WRONG: @AppStorage("authToken") private var token = ""// CORRECT: Use saveToKeychain(account:data:service:)``` ## Data Protection iOS encrypts files based on their protection class: | Class | When Available | Use For ||---|---|---|| `.complete` | Only when unlocked | Sensitive user data || `.completeUnlessOpen` | Open handles survive lock | Active downloads, recordings || `.completeUntilFirstUserAuthentication` | After first unlock (default) | Most app data || `.none` | Always | Non-sensitive, system-needed data | ```swift// Set file protectiontry data.write(to: url, options: .completeFileProtection) // Check protection levellet attributes = try FileManager.default.attributesOfItem(atPath: path)let protection = attributes[.protectionKey] as? FileProtectionType``` Use `.complete` for any file containing user-sensitive data. The default`.completeUntilFirstUserAuthentication` is acceptable for general app data. ## CryptoKit Use CryptoKit for all cryptographic operations. Do not use CommonCrypto or theraw Security framework for new code. ### Symmetric Encryption (AES-GCM) ```swiftimport CryptoKit let key = SymmetricKey(size: .bits256) func encrypt(_ data: Data, using key: Symmet