Join our Newsletter — 33% off our NHI Course
Home› Guides› iOS App Security Guide: Keychain, App Transport Security…
Guide Application Security

iOS App Security Guide: Keychain, App Transport Security and App Attest

PDF for newsletter subscribers · free to read online

← All guides
By Lalit Choda, NHI Mgmt Group Updated 24 October 2026 15 min read
On this page

App Store review does not make an iOS app secure: it does not scan your code for hard-coded secrets, and it does not stop you storing tokens in the wrong Keychain class or switching App Transport Security off. iOS gives developers strong building blocks, including Data Protection, the Keychain, the Secure Enclave, App Transport Security (ATS) and App Attest, but each one depends on choices made in code, entitlements and Info.plist. This guide is the iOS-specific companion to the cross-platform Mobile App Security Guide. It gives the constants, keys and server-side verification steps an iOS engineer needs, plus privacy manifest duties, a rollout plan, metrics and failure patterns. It is written for iOS developers, mobile security engineers and the backend teams that verify what iOS apps send them.

Key takeaways

  • Pick the Data Protection and Keychain class deliberately. Third-party app files default to Class C (protected until first user authentication) and Keychain items default to "when unlocked". Use the most restrictive class that still lets the feature work, and the ThisDeviceOnly variants for tokens.
  • Secure Enclave keys cannot leave the device. They are NIST P-256 only, must be created inside the enclave and cannot be imported, which makes them the right anchor for device-bound tokens.
  • ATS is on by default; every exception is a finding. ATS requires TLS 1.2 or later with forward secrecy, and NSAllowsArbitraryLoads and similar exceptions need justification at App Store review.
  • App Attest only helps if the server verifies it. The backend must check the certificate chain, nonce, App ID hash, environment and an increasing counter on every assertion.
  • Never ship secrets in the IPA. Cybernews found hard-coded secrets in 71% of the iOS apps it analysed. Attest the app, then exchange the attestation for a short-lived token bound to a Secure Enclave key.

Data Protection classes for files

Every file on iOS is encrypted with a per-file key wrapped by a class key. The class decides when the file can be read. Apple's Platform Security guide describes four classes:

ClassFile protection constantWhen the data is readableTypical use
A: Complete ProtectionNSFileProtectionCompleteOnly while unlocked; the class key is discarded shortly after lockHealth records, documents, cached personal data
B: Protected Unless OpenNSFileProtectionCompleteUnlessOpenFiles can be written while locked; key wiped when the file closesDownloads or recordings finishing in the background
C: Protected Until First User AuthenticationNSFileProtectionCompleteUntilFirstUserAuthenticationAfter the first unlock following a restart, until the next restartDefault for third-party app data; data needed by background tasks
D: No ProtectionNSFileProtectionNoneAlways; protected only by the device UIDAvoid for anything sensitive

Because Class C is the default, data written by an app stays readable while the phone is locked in a pocket after its first unlock. Set Class A explicitly for files that do not need background access, either through the Data Protection entitlement or per file when you write it. Also review where data leaks outside your files: caches, WebView storage, screenshots taken when the app moves to the background, and logs.

Keychain accessibility and access control

The Keychain is an encrypted SQLite database. Apple's guide describes per-row AES-256-GCM keys that need a round trip through the Secure Enclave, and access control lists evaluated inside the Secure Enclave. Each item has an accessibility class that mirrors the file classes.

Accessibility valueEquivalent file classBackup and migrationUse for
kSecAttrAccessibleWhenUnlocked (default)Class AMigrates to a new deviceForeground-only credentials that may move with the user
kSecAttrAccessibleWhenUnlockedThisDeviceOnlyClass ARestorable only to the same deviceSession and refresh tokens, device-bound keys
kSecAttrAccessibleAfterFirstUnlock / ...ThisDeviceOnlyClass CPlain variant migrates; ThisDeviceOnly does notTokens needed by background refresh
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnlyClass A, passcode requiredNever synced to iCloud Keychain, never backed up; unusable if the passcode is removedHighest-value secrets
kSecAttrAccessibleAlwaysClass DMigratesNot recommended by Apple
  • Use ThisDeviceOnly for tokens: Apple's documentation states that ThisDeviceOnly items are restored only to the device that made the backup, so a stolen backup or a new phone does not inherit the session.
  • Add user presence where it matters: access control can require Face ID, Touch ID, Optic ID or the passcode, and can invalidate the item when biometric enrolment changes. Use biometrics to release a key or token, not as a yes or no answer that the app then trusts.
  • Scope sharing with access groups: Keychain items can only be shared between apps from the same developer, enforced through the keychain-access-groups, application identifier and app group entitlements. Do not put tokens in a shared group unless every app in it needs them.

Secure Enclave keys

The Secure Enclave is a hardware key manager isolated from the main processor, present on iPhones from the iPhone 5s (A7) onwards. Apple's documentation is precise about its limits: it supports only 256-bit NIST P-256 elliptic curve keys, for signing and for ECDH key agreement; keys must be generated inside it and cannot be imported; and the app never sees the private key, only signatures or decryption results.

let access = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
    kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
    [.privateKeyUsage, .biometryAny], nil)!
let attributes: NSDictionary = [
    kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
    kSecAttrKeySizeInBits: 256,
    kSecAttrTokenID: kSecAttrTokenIDSecureEnclave,
    kSecPrivateKeyAttrs: [kSecAttrIsPermanent: true,
                          kSecAttrApplicationTag: tag,
                          kSecAttrAccessControl: access]]
// SecKeyCreateRandomKey(attributes, &error), then SecKeyCopyPublicKey to register it
  • Include .privateKeyUsage: Apple notes that without it key generation succeeds but signing fails.
  • Use the key for proof of possession: register the public key with your backend at sign-in and sign each sensitive request or token refresh. CryptoKit's SecureEnclave types offer the same capability with a simpler API.
  • Plan for loss: because keys never leave the device, a new phone or a restore means re-enrolment. Make that path as strong as first sign-in.

App Transport Security and network trust

ATS is on for apps built with the iOS 9 SDK or later and applies to the URL loading system (URLSession). Beyond normal certificate validation, Apple lists these extended requirements: TLS 1.2 or later, AES-128 or AES-256, forward secrecy through ECDHE key exchange, RSA keys of at least 2048 bits or ECC keys of at least 256 bits, and SHA-256 or stronger certificate digests.

Info.plist key under NSAppTransportSecurityEffectReview position
NSAllowsArbitraryLoadsDisables ATS for all connections not listed in NSExceptionDomainsNeeds App Store justification; block in release
NSAllowsArbitraryLoadsInWebContentDisables ATS for web views onlyNeeds justification; only for browsers or apps showing arbitrary web content
NSAllowsArbitraryLoadsForMediaDisables ATS for AV Foundation mediaNeeds justification; encrypted, non-personal media only
NSAllowsLocalNetworkingAllows loads from local resourcesAcceptable for local device setup flows
NSExceptionDomains with NSExceptionAllowsInsecureHTTPLoads or NSExceptionMinimumTLSVersionWeakens rules for one named domainNeeds justification; scope to the exact host and set an end date
NSPinnedDomainsDeclares the certificates ATS expects for named domainsStrengthens trust; ship backup keys
  • Fix the server, not the app: Apple's guidance is to upgrade server security before adding exceptions and to use the narrowest exception possible. The nscurl tool shows which exceptions a given server needs.
  • Remember what ATS does not cover: lower-level networking and custom trust evaluation outside URLSession are your responsibility. Never return success from a server trust challenge without evaluating it.
  • Pin with care: pinning through NSPinnedDomains or code needs a backup key and a forced-update path, or a certificate change will break every installed copy.

App Attest and DeviceCheck

App Attest, part of the DeviceCheck framework, lets your server confirm that a request comes from a genuine instance of your app on genuine Apple hardware. DeviceCheck's older per-device bits serve a different purpose.

Client flow

  1. Check DCAppAttestService.shared.isSupported. If it is false, degrade gracefully and tell the server not to expect assertions for that client. Only some app extension types are supported.
  2. Call generateKey once per user account per device and store the returned key identifier; it cannot be recovered later.
  3. Fetch a one-time server challenge of at least 16 bytes, hash it with SHA-256 and call attestKey(_:clientDataHash:). Send the attestation object to the server. Retry with the same key on serverUnavailable; for other errors discard the key and create a new one.
  4. For sensitive requests, combine a fresh challenge with the request data, hash it and call generateAssertion. Send the assertion with the request.

Server verification

CheckAttestationAssertion
Certificate chainx5c chain validates to Apple's App Attest rootSignature verifies with the stored public key
NonceSHA-256 of authData plus clientDataHash equals the value in extension OID 1.2.840.113635.100.8.2Signature is over SHA-256 of authenticatorData plus clientDataHash; embedded challenge matches
App identityRP ID equals SHA-256 of TeamID.BundleIDSame
CounterEquals 0Strictly greater than the last stored value
Environmentaaguid is appattestdevelop or appattest (production)Key belongs to the expected environment
BindingKey ID matches the hash of the public key; key not already linked to another userRequest belongs to the user the key was registered to
  • Know the key lifetime: attested keys survive app updates but not reinstall, device migration or restore from backup. A user with many new keys in a short time is a fraud signal.
  • Use the receipt: the attestation receipt lets your server ask Apple for a fraud risk metric showing how many attested keys a device has, which helps spot one compromised device serving many app instances.
  • Roll out gradually: Apple advises apps with large user bases to onboard users gradually rather than calling attestKey for everyone at once.
  • Use DeviceCheck bits for coarse state: DCDevice generates a token the server sends to Apple's query_two_bits, update_two_bits and validate_device_token endpoints, authenticated with an ES256 JWT. Two bits per device suit flags such as "promotion already claimed".

Treat App Attest as one signal. It shows the app is genuine, not that the user is honest or that the device is free of malware. See the Device Intelligence and Fingerprinting Guide for combining signals.

Where identity fits: secrets, tokens and passkeys

An iOS app is a public client. The iOS apps hard-coded secrets research found more than 815,000 secrets across 156,080 App Store apps, including 19 Stripe secret keys, and 836 storage endpoints that needed no authentication. Symantec's earlier hard-coded AWS keys research found that about 98% of 1,859 affected apps were iOS apps, many with keys inherited from shared SDKs.

  1. Keep provider keys on the server: payment, cloud storage and AI keys belong in a vault behind your API. See the Secrets Management Guide.
  2. Attest, then exchange: the backend verifies App Attest and user authentication, then issues a short-lived token bound to a Secure Enclave public key. The app stores it with a ThisDeviceOnly class and signs refreshes with the enclave key.
  3. Restrict keys that must ship: analytics or mapping keys should be limited by bundle ID and API scope in the provider console and monitored. See the API Key Management Guide.
  4. Use passkeys for people: ASAuthorizationPlatformPublicKeyCredentialProvider creates and uses passkeys for a relying party ID, and requires an associated domain with the webcredentials service. See the Passwordless and Passkeys Guide.
  5. Protect distribution credentials: signing certificates and App Store Connect API keys used by CI can publish code to every user; keep them in a managed signing service with named owners. See the Code Signing Security Guide.

Privacy manifests and required-reason APIs

Apple requires a PrivacyInfo.xcprivacy property list in apps and in third-party SDKs that collect data or use certain APIs. Security teams should treat it as a declared data-flow inventory and check it against observed traffic.

  • NSPrivacyTracking and NSPrivacyTrackingDomains: declare whether data is used for tracking and list the tracking domains. If the user has not granted tracking permission, requests to those domains fail.
  • NSPrivacyCollectedDataTypes: the data types collected, which should match the App Store privacy label.
  • NSPrivacyAccessedAPITypes: each required-reason API category used, with approved reason codes. Since 1 May 2024 App Store Connect does not accept apps that use these APIs without declaring reasons. Apple prohibits fingerprinting whether or not the user grants tracking permission.
  • SDKs declare their own use: each SDK must report its own required-reason API use in its own manifest, and SDKs on Apple's list of commonly used SDKs need a manifest and a signature. Use Xcode's privacy report to review the combined result at release.

Choosing controls by app risk

ControlLow-risk appRegulated or high-value app
FilesDefault Class C, nothing sensitive cachedClass A for personal data; background data reviewed case by case
TokensKeychain, WhenUnlockedThisDeviceOnlyToken bound to a Secure Enclave key, biometric gate for high-value actions
NetworkATS with no exceptionsATS with no exceptions plus pinning with backup keys
IntegrityApp Attest at sign-in, observe onlyAssertions on sensitive requests, fraud risk metric, enforcement
VerificationOWASP MASVS baselineMASVS including the resilience group, independent MASTG testing

Small teams should focus on removing embedded secrets, choosing ThisDeviceOnly Keychain classes and keeping ATS exception-free. Larger organisations with several apps should run one shared attestation and token service so verification logic is written and reviewed once.

Implementation roadmap

  1. Inventory: list apps, SDKs, entitlements, ATS keys and Keychain classes in use; scan the built IPA for secrets.
  2. Remove and rotate secrets: move provider keys server-side, rotate everything that has shipped, and use remote configuration so future rotation does not break installed versions.
  3. Fix storage classes: migrate tokens to ThisDeviceOnly items and set Class A on sensitive files in one release, with a read-old, write-new migration.
  4. Remove ATS exceptions: upgrade the servers, then delete exceptions; fail the build if NSAllowsArbitraryLoads appears in a release Info.plist.
  5. Deploy App Attest in observe mode: verify on the server and log results without blocking, using the development environment first and gradual onboarding in production.
  6. Enforce in stages: require assertions for the most sensitive actions first. Roll back by switching server policy to observe, which needs no app release.
  7. Gate releases: MASTG-based tests, a secrets scan and a privacy report review on every release, plus a minimum supported version.

Detection and measurement

  • Log on the server: attestation and assertion failures by reason (chain, nonce, counter, environment), keys per user, and requests without a valid device-bound token.
  • Watch counters and keys: a repeated or decreasing assertion counter means replay; bursts of new keys for one account suggest automation.
MetricTarget
Hard-coded secrets found in release IPAsZero; any finding blocks release
ATS exceptions in release buildsZero without a recorded justification and end date
Tokens stored with a ThisDeviceOnly class100%
Sensitive API calls with a verified assertionAbove 95% of supported devices
SDKs with a reviewed privacy manifest100%

Framework mapping

AreaOWASP MASVS groupNIST SP 800-53 Rev. 5NIST CSF 2.0MITRE ATT&CK
Data Protection and KeychainMASVS-STORAGESC-28PR.DS-01T1409 Stored Application Data; T1634 Credentials from Password Store (Mobile)
Secure Enclave keysMASVS-CRYPTOSC-12PR.DS-01n/a
App Transport SecurityMASVS-NETWORKSC-8PR.DS-02T1638 Adversary-in-the-Middle (Mobile)
Embedded secrets and token exchangeMASVS-AUTHIA-5PR.AA-01T1552.001 Credentials In Files (Enterprise)
App AttestMASVS-RESILIENCESI-7PR.PS-06n/a
Privacy manifestsMASVS-PRIVACYSA-11PR.PS-06n/a

The mapping is NHI Mgmt Group's own. For the risk view, see the OWASP Mobile Top 10 Guide.

Common failure patterns

  • Secrets in the bundle: Stripe, cloud and Firebase credentials in Info.plist, config files or code, as the iOS apps hard-coded secrets research showed at scale.
  • Default classes left alone: refresh tokens in kSecAttrAccessibleAfterFirstUnlock or WhenUnlocked without ThisDeviceOnly, so they migrate with backups, or tokens in UserDefaults and plists.
  • Global ATS exceptions: NSAllowsArbitraryLoads added for one legacy server and never removed.
  • App Attest without server checks: the app calls attestKey but the server never checks the counter, the RP ID or the environment, so development keys and replays pass.
  • Biometric yes or no: the app trusts a LocalAuthentication result as the security decision instead of using it to release a Keychain item or enclave key.
  • Unreviewed SDKs: an SDK collects data or uses required-reason APIs the app's own declarations do not mention, which shows up in review or in traffic analysis.

Practitioner checklist

  • Scan every release IPA for secrets and rotate any key that has ever shipped.
  • Store tokens in the Keychain with a ThisDeviceOnly class and set Class A on sensitive files.
  • Bind sessions to Secure Enclave P-256 keys and sign refreshes with them.
  • Keep ATS exception-free in release builds and block NSAllowsArbitraryLoads in CI.
  • Verify App Attest on the server: chain, nonce, RP ID, environment and increasing counter.
  • Roll out attestation in observe mode first, with server-side rollback.
  • Adopt passkeys with ASAuthorizationPlatformPublicKeyCredentialProvider and the webcredentials associated domain.
  • Maintain PrivacyInfo.xcprivacy for the app and require manifests from every SDK.
  • Protect signing certificates and App Store Connect API keys as privileged non-human credentials.

Standards and references

Related NHI Mgmt Group resources: Mobile App Security Guide · Android App Security Guide · Mobile App Security Testing Guide · Mobile Device Security Guide · Secrets Management Guide

PDF for subscribers

Take this guide with you

Every section, table and checklist in one PDF, with links to the sources and related guides. Subscribe to our weekly NHI & AI Identity Journal and we’ll email you a download link.

Free weekly newsletter

Subscribe to the NHI & AI Identity Journal

The latest on NHI and Agentic AI security – articles, research, breaches, news and events every week.

Bonus 33% off our NHI Course when you subscribe.

NHIMG Editorial Note
Written and reviewed by Lalit Choda, NHI Mgmt Group. Last updated 24 October 2026.
NHI Mgmt Group — the #1 independent authority on Non-Human Identity, IAM, and Agentic AI security. nhimg.org

PDF Downloads for Newsletter Subscribers

Get the guide

Enter your details and we’ll email you a download link.

The full guide is free to read online. The PDF is a thank you for subscribing.

Fill in all fields marked * and tick the PDF box to continue.