Learn Swift - Secure Coding & Data Protection
Series/Learn Swift/Episode 11
Episode 11 of 23

Learn Swift - Secure Coding & Data Protection

This episode covers Swift application security: secure coding practices and data validation, storing credentials in the Keychain, basic encryption and hashing with CryptoKit, plus secure storage, sandboxing, and privacy protection on Apple platforms.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Security is not a feature bolted on at the end — it is a design decision that permeates every layer of an application. Episode 11 covers secure coding and data protection in Swift: input validation practices, storing secrets in the Keychain, encryption and hashing with CryptoKit, and how Apple platforms protect data through sandboxing and privacy.

In a world where user data is the attacker's primary target, a careless application can leak sensitive data even while "working" perfectly. This episode gives you the foundation to build an application that is secure from the first line.

Secure Coding and Data Validation

Secure Coding Principles

Four principles govern all security practices:

  • Trust no input: all external data is considered untrusted until validated.
  • Least privilege: give each component the minimal access it needs.
  • Fail safe: failures must close access, not open it.
  • Defense in depth: layer your defenses; don't rely on a single mechanism.

Validating Incoming Data

Validation happens as close to the input source as possible, using whitelists rather than blacklists:

Simple input validation
struct Validator {
    static func emailValid(_ email: String) -> Bool {
        let pola = "^[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}$"
        return email.range(of: pola, options: .regularExpression) != nil
    }
 
    static func rentangUmur(_ nilai: Int) -> Bool {
        return (13...120).contains(nilai)
    }
}
 
print(Validator.emailValid("arman@example.com"))
print(Validator.rentangUmur(200))

email.range(of:options:.regularExpression) checks the email against a whitelist pattern. Validating with explicit ranges like (13...120).contains(nilai) rejects out-of-bounds values from the start — far safer than cleaning up bad values afterward.

Keychain for Credentials

Storing Secrets Safely

The Keychain is a system-level encrypted storage for secrets — tokens, passwords, and other sensitive data. Unlike UserDefaults and files, Keychain data is encrypted and tied to the device and user:

Writing to the Keychain
import Security
 
func simpanKeychain(_ data: Data, untuk key: String) -> OSStatus {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrAccount as String: key,
        kSecValueData as String: data
    ]
    return SecItemAdd(query as CFDictionary, nil)
}

SecItemAdd(query, nil) stores data in the Keychain; the kSecClassGenericPassword attribute marks the entry as a generic password. This function returns an OSStatus that must be checked — errSecSuccess means success.

Reading Secrets from the Keychain

Reading it back is done with a search query:

Reading from the Keychain
func ambilKeychain(key: String) -> Data? {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrAccount as String: key,
        kSecReturnData as String: true,
        kSecMatchLimit as String: kSecMatchLimitOne
    ]
    var item: CFTypeRef?
    let status = SecItemCopyMatching(query as CFDictionary, &item)
    return status == errSecSuccess ? item as? Data : nil
}

SecItemCopyMatching(query, &item) returns the stored Data if found. All application secrets — API tokens, credentials — must go through this path, not global variables or plist files that are easy to extract.

Encryption and Hashing with CryptoKit

Hashing with SHA-256

To verify integrity or create a fingerprint of data, use hashing — a one-way function that cannot be reversed:

SHA-256 with CryptoKit
import CryptoKit
 
let pesan = Data("pesan rahasia".utf8)
let digest = SHA256.hash(data: pesan)
print(digest.map { String(format: "%02x", $0) }.joined())

SHA256.hash(data: pesan) produces a 32-byte digest. CryptoKit provides a hardware-optimized, audited implementation — never write your own cryptographic algorithms; always use a trusted library.

Symmetric Encryption with AES-GCM

To store sensitive data you need to read back, use symmetric encryption with AES-GCM:

AES-GCM encryption
let key = SymmetricKey(size: .bits256)
let plainData = Data("isi rahasia".utf8)
 
let sealed = try AES.GCM.seal(plainData, using: key)
let dibuka = try AES.GCM.open(sealed, using: key)
print(String(data: dibuka, encoding: .utf8)!)

AES.GCM.seal(plainData, using: key) encrypts the data and includes an authentication tag that detects tampering. Store the key safely in the Keychain — combining CryptoKit encryption with the Keychain is the most common pattern for protected data storage.

Secure Storage, Sandboxing, and Privacy

Sandbox and File Protection

iOS apps run in a sandbox: access to the system is limited to your own container. Data inside the container can be protected further with Data Protection — files are encrypted automatically and can only be accessed while the device is unlocked:

Writing a protected file
let data = Data("catatan pribadi".utf8)
try data.write(to: fileURL,
               options: [.completeFileProtection])

.completeFileProtection makes a file accessible only while the device is unlocked. Other protection levels — .completeFileProtectionUnlessOpen and .noFileProtection — balance security against availability when notifications arrive.

Privacy and Transparency

iOS requires you to declare the reason for every access to personal data (camera, location, photos) in Info.plist through keys like NSCameraUsageDescription. Users also see an indicator when that data is accessed. Beyond compliance, good privacy practice means:

  • Collect the minimum amount of data.
  • Process data locally instead of sending it to a server without reason.
  • Delete data when it's no longer needed.
  • Never write secrets to logs.

Warning

Secrets written to logs are one of the most common leaks. Enforce a strict rule: credentials and tokens never enter print, NSLog, or crash reports.

Closing

Key takeaways:

  • Validate all external input with whitelists and explicit ranges.
  • The Keychain is the only right place to store secrets on a device.
  • SHA-256 hashing verifies integrity; AES-GCM protects data you need to read back.
  • Sandbox and Data Protection encrypt app files automatically.
  • Declare the reason for personal data access in Info.plist and respect user privacy.
  • Never write credentials or tokens into logs.

In the next episode, episode 12, we'll cover authentication and authorization — implementing OAuth 2.0 and OpenID Connect in Swift apps, integrating Sign in with Apple, managing tokens and refresh tokens, and consuming APIs securely with HTTP security headers. Your security extends to the server side!

Learn Swift - Secure Coding & Data Protection | Learn Swift