Skip to content
AgileLogics
6 min read

Security Fundamentals

Prerequisites: Networking with URLSession, Files and FileManager

Apps hold personal data and credentials, and they run on devices you don't control. A few practices cover most of the risk.

Store secrets in the Keychain

Tokens, passwords, and keys go in the Keychain — the system's encrypted credential store — never in UserDefaults or plain files, which are stored unencrypted in the app's container.

import Foundation
import Security

func saveToken(_ token: String, account: String) -> Bool {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrAccount as String: account,
        kSecValueData as String: Data(token.utf8),
        kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock,
    ]
    SecItemDelete(query as CFDictionary)   // replace any existing item
    return SecItemAdd(query as CFDictionary, nil) == errSecSuccess
}

The raw Keychain API is verbose, so most projects wrap it in a small helper type or use a well-maintained package.

Don't ship secrets in the app

Anything inside an app bundle — API keys, passwords, private URLs — can be extracted by anyone who downloads it. Keep secrets on your server and have the app authenticate to it with per-user tokens.

Network security

  • HTTPS only. App Transport Security blocks plain http:// by default. Don't add blanket exceptions to Info.plist.
  • Validate on the server. Anyone can modify requests an app sends; treat all client input as untrusted on the back end.
  • For high-risk apps (banking, health), consider certificate pinning, which rejects connections to servers presenting unexpected certificates.

Cryptography: use the platform, not your own

CryptoKit provides modern, safe primitives on Apple platforms (and the open-source swift-crypto package offers the same API on Linux, imported as Crypto instead of CryptoKit):

import CryptoKit
import Foundation

let digest = SHA256.hash(data: Data("hello".utf8))
print(digest.map { String(format: "%02x", $0) }.joined())

let key = SymmetricKey(size: .bits256)
let sealed = try AES.GCM.seal(Data("secret".utf8), using: key)
let opened = try AES.GCM.open(sealed, using: key)
print(String(decoding: opened, as: UTF8.self))
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
secret

Never invent your own encryption scheme, and don't hash passwords with a fast hash like SHA-256 on a server — use a dedicated password-hashing algorithm such as bcrypt or Argon2.

Privacy

  • Request permissions (camera, location, contacts) only when the feature needs them, with a clear usage description string.
  • Declare the data you collect in your app's privacy manifest, which App Store review requires.
  • Don't log personal data or tokens — device logs can be read by diagnostic tools.

Common mistakes

  • Storing an auth token in UserDefaults.
  • Trusting data because it came from your own app. The server must check permissions on every request.