Day 21 – Security Best Practices for iOS Developers (Keychain, Encryption, Secure Storage)

Security is not optional — it’s mandatory. iOS apps often handle personally identifiable information, payment credentials, health data, and other sensitive material. Apple’s ecosystem gives you powerful primitives (Keychain, Secure Enclave, Data Protection, App Transport Security), but security is only effective when applied correctly across the entire app lifecycle: architecture, storage, networking, authentication, build & CI, distribution, and monitoring. Below is a comprehensive, production-ready guide covering all mandatory details iOS developers must know — practical, prescriptive, and battle-tested (the same approach we teach in CuriosityTech.in courses while building real apps).


High-level security goals (the security mindset)

  • Confidentiality: sensitive data must remain secret (encryption in transit & at rest).

  • Integrity: data must not be tampered with (signing, checksums).

  • Authenticity: verify identities (certificates, tokens).

  • Least privilege: request only what you need.

  • Defense-in-depth: many layers — don’t rely on a single control.


1) Secure storage on device

Keychain (recommended for secrets)

  • Use Keychain Services for credentials, tokens, private keys. Keychain is encrypted and managed by the OS.

  • Choose appropriate accessibility constants:

    • kSecAttrAccessibleWhenUnlocked — accessible only when device unlocked (common for session tokens).

    • kSecAttrAccessibleAfterFirstUnlock — useful for background tasks that run after first unlock.

    • kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly — strongest; requires passcode and is device-specific.

  • Prefer kSecAttrAccessibleWhenUnlockedThisDeviceOnly or WhenPasscodeSetThisDeviceOnly for highly sensitive secrets to avoid keychain migration to backups/devices.

  • Never store secrets in UserDefaults, plist files, or plain files.

Practical pattern (conceptual): store OAuth refresh tokens, JWT signing keys, API keys that must stay on device, using Keychain wrappers (e.g., wrapper in your project). Avoid storing long-lived secrets if possible.

Secure Enclave & Private Keys

  • Generate and store asymmetric private keys in Secure Enclave when you need hardware-backed keys (signing, biometric-backed authentication).

  • Use kSecAttrTokenIDSecureEnclave when creating keys.

  • Private keys in Secure Enclave cannot be exported — good for cryptographic proof of device possession.

File-based storage & encryption

  • If you must store files (images, docs), encrypt them before saving to disk. Use AES-GCM or AES-CBC+HMAC with well-managed keys.

  • Prefer storing encryption keys in Keychain and use them to decrypt files on demand.

  • Use FileProtection attributes:

    • NSFileProtectionComplete for most sensitive files (available only when device unlocked).

    • NSFileProtectionCompleteUnlessOpen or CompleteUntilFirstUserAuthentication for background needs.

Data protection classes (iOS)

  • Respect data protection classes and map them to your file and keychain strategy.

  • For photos or documents that require offline access, choose protection levels carefully (tradeoff between availability and security).


2) Networking: encryption & authentication

App Transport Security (ATS)

  • ATS enforces HTTPS/TLS for network requests by default. Do not disable ATS. Apple requires reasons for exceptions and may reject apps that weaken transport security.

  • Use TLS 1.2+ (TLS 1.3 preferred), strong ciphers, and forward secrecy.

Certificate Pinning

  • Implement certificate pinning (public key pinning or leaf certificate pinning) to mitigate MitM attacks against compromised CAs.

  • Pin carefully:

    • Pin public key hashes rather than full certs to allow certificate rotation.

    • Provide a fallback and pin rotation strategy (backup keys).

  • Use libraries cautiously; consider URLSession + custom URLSessionDelegate didReceive challenge for pinning.

OAuth PKCE & Token handling

  • For public clients (mobile apps), use OAuth 2.0 Authorization Code Flow with PKCE (Proof Key for Code Exchange). Don’t use implicit flow.

  • Keep access tokens short-lived; refresh tokens should be securely stored (Keychain).

  • Use refresh token rotation on backend to limit replay.

Secure cookies & cookie storage

  • If using cookies, ensure Secure, HttpOnly, and proper SameSite attributes are set by server. Avoid storing session identifiers in app storage.

Certificate validation & error handling

  • Validate certificate chain and hostnames; handle TLS errors by failing safely (don’t silently accept invalid certs).

  • Log failures for monitoring but avoid logging sensitive details.


3) Authentication & biometrics

Biometric authentication (Face ID / Touch ID)

  • Use LocalAuthentication for optional convenience (unlocking secrets from Keychain).

  • Combine biometrics with Keychain access controls (use access control flags like kSecAccessControlBiometryAny or kSecAccessControlUserPresence).

  • Design fallback flows for biometric failures (PIN fallback) and consider user opt-in.

Session management & sign out

  • Invalidate tokens on logout (revoke on server where possible). Delete tokens from Keychain.

  • Implement silent token refresh, with safe retry logic and exponential backoff.

  • Limit concurrent sessions or provide session management UI (view/terminate sessions).


4) Sensitive data handling & privacy

Minimize collection

  • Collect only required data; justify each permission to user. Apple requires transparency (App Privacy fields).

  • For HealthKit, location, camera, microphone — explain the purpose in the Info.plist usage strings (NSHealthShareUsageDescription, NSLocationWhenInUseUsageDescription, etc.).

Local logs & crash reports

  • Avoid logging PII, tokens, or raw request/response bodies.

  • Use crash reporting tools (Firebase Crashlytics, Sentry) but scrub sensitive data before sending.

  • In development, keep verbose logs off for release builds.

GDPR / Privacy regulations

  • Provide consent flows where necessary, data deletion requests, and a privacy policy URL.

  • Implement data export / delete flows if required.


5) Secure coding practices

Input validation & sanitization

  • Validate inputs client-side for UX, but enforce all validation server-side.

  • Protect against injection vectors (though less common on mobile, still relevant for local interpreters, SQL in local DB, or file parsing).

Use HTTPS + JSON parsers defensively

  • When parsing JSON, use Codable safely; fail gracefully on unexpected input.

  • Limit parser recursion depth for large or malicious payloads.

Avoid embedding secrets in code

  • Do not hardcode API keys, secret tokens, or private keys in source code or resource files.

  • Secrets in the codebase are easily extracted from binaries.

Code obfuscation and symbol stripping

  • Strip debug symbols in release builds to make reverse-engineering harder.

  • Consider lightweight obfuscation for string literals and classes (note: obfuscation is not a security boundary; mainly raises attacker effort).


6) Protecting build pipeline & secrets in CI

Secret management

  • Store certificates, API keys, provisioning profiles in secure secret stores (GitHub Actions secrets, Bitrise secrets, HashiCorp Vault).

  • For code signing use Fastlane Match (store certs in encrypted repos) or use Apple Developer-managed signing with proper access controls.

Avoid committing secrets

  • Never commit GoogleService-Info.plist or other secrets to public repos unless they are safe to be public.

  • Use environment variables and secret injection at build time.

Reproducible & auditable CI

  • Ensure only authorized contributors can trigger releases. Keep audit logs of who uploaded what to App Store Connect.


7) Binary & runtime protections

Jailbreak/root detection

  • Consider detecting jailbreak/root for apps handling high-risk data (banking, enterprise). Methods:

    • Check for existence of typical jailbreak files, ability to write outside sandbox, etc.

  • Be cautious: jailbreak detection can be circumvented and may produce false positives. Use it as part of broader risk assessment (not sole defense).

Runtime integrity checks

  • Verify code signature at runtime (don’t trust unchecked executables).

  • Detect tampering with resources (checksums, signed manifests).


8) APIs & backend collaboration (server-side matters)

  • Security is end-to-end — backend must validate and authorize all requests.

  • Use per-client credentials, rate limits, anomaly detection, and logging.

  • Implement server-side revocation of tokens and session blacklisting.


9) Third-party libraries & supply-chain security

  • Use vetted packages. Keep dependencies up to date.

  • Use SCA (Software Composition Analysis) tools to detect vulnerable versions.

  • Pin package versions and audit transitive dependencies.

  • Prefer Swift Package Manager or CocoaPods with version locking; avoid loading remote code at runtime.


10) Testing security (mandatory)

Static analysis & SAST

  • Run static analysis: Xcode’s analyzer, third-party tools (e.g., MobSF, AppSweep).

  • Look for insecure APIs, weak crypto, or unsafe deserialization.

Dynamic testing & DAST

  • Pen-test typical flows: authentication, token theft, session fixation, local file exposure.

  • Test under proxy (Charles/Fiddler) to ensure TLS and pinning behave.

Fuzzing & instrumentation

  • Fuzz inputs to parsers and local data stores. Use Instruments for memory and performance.

Threat modeling

  • Do a simple STRIDE/OWASP Mobile threat model for your app and enumerate mitigations.


11) Common vulnerabilities & mandatory mitigations

Below are frequent pitfalls and required fixes.

VulnerabilityWhy it mattersMandatory fix
Secrets in codeEasy extraction from binaryRemove secrets → use Keychain & backend
HTTP or weak TLSMitM riskEnforce ATS (HTTPS/TLS 1.2+), pin certs
Storing tokens insecurelyToken theftStore in Keychain; use short lifetimes
Unprotected backupsSensitive data leaked via backupsUse ThisDeviceOnly or encryption
Insufficient permissions justificationApp rejection or privacy breachProvide clear Info.plist reason strings
Excessive loggingPII leakStrip logs in release, redact before sending

12) Secure app distribution & App Store requirements

  • Provide accurate App Privacy metadata (data collected, linked to user).

  • For health, financial, or sensitive apps, include required documentation for review and test accounts.

  • If using third-party trackers, disclose them and follow Apple’s privacy rules.


13) Checklist you can use before release (copyable)

  • No secrets hardcoded in code or resources.

  • All tokens stored in Keychain with appropriate accessibility.

  • TLS enforced, ATS not weakened.

  • Certificate pinning implemented (or strong server-side protections).

  • OAuth PKCE used for public clients.

  • Biometric flows use Secure Enclave / Keychain access control.

  • File protection attributes set for sensitive files.

  • Crash reports scrubbed of sensitive info.

  • Third-party libs audited and up-to-date.

  • CI/CD secrets stored securely; build artifacts reproducible.

  • Privacy strings added (Info.plist) and privacy policy linked.

  • Threat model documented and tested.

  • Test accounts and notes ready for App Store review.


14) Tools & libraries (practical list)

  • Keychain: Apple Keychain services (native).

  • Crypto: CryptoKit (preferable modern API), CommonCrypto when needed.

  • Network: URLSession + TLS; use custom delegate for pinning.

  • Dependency scanning: OWASP Dependency-Check, Snyk, GitHub Dependabot.

  • Mobile security testing: MobSF (Mobile Security Framework), Frida (dynamic), Burp Suite (proxy).

  • CI secrets: GitHub Secrets, Bitrise Secrets, Vault.

  • Crash reporting: Firebase Crashlytics, Sentry (configure scrubbing).


15) Becoming an expert (career roadmap)

  • Master Apple security primitives: Keychain, Secure Enclave, Data Protection.

  • Learn modern cryptography basics and how to use CryptoKit safely.

  • Study OAuth 2.0, OpenID Connect, PKCE, and token lifecycle management.

  • Practice threat modeling and conduct security reviews for projects.

  • Run static & dynamic security tests as part of CI.

  • Keep up-to-date with OWASP Mobile Top 10 and Apple’s platform security updates.

  • Participate in responsible disclosure programs to learn real-world exploits.


Diagram — simplified end-to-end secure flow


Conclusion

Security must be engineered at every level — device storage, app runtime, network transport, build pipeline, and backend. Apple provides excellent building blocks (Keychain, Secure Enclave, ATS, Data Protection), but correct use and defense-in-depth are what make production apps secure. Follow minimum mandatory practices: never hardcode secrets, always use Keychain, enforce TLS, use OAuth PKCE, secure CI secrets, and audit third-party libraries. These are the standards CuriosityTech.in trains engineers to apply in real projects so they ship apps that are secure, compliant, and trusted.


Leave a Comment

Your email address will not be published. Required fields are marked *