Description
Storing passwords, tokens, API keys, or other sensitive values in plaintext in a local Core Data or Realm database can expose them through backups, debugging tools, or a jailbroken device.
Potential impact
- Theft of authentication tokens or sessions.
- Exposure of sensitive information through local backups or debugging tools.
- Account access through reuse of stolen values.
Remediation
- Avoid storing sensitive values in a local database where possible.
- When storage is necessary, use established secure storage such as Keychain, SQLCipher, or Realm with an encryption key.
- Encrypt individual values before storing them in the database and manage the key in Keychain.
Examples
The after example assumes that the Core Data access_token attribute has the Binary Data type. Key retrieval and saving the context are omitted.
Before
swift
let user = NSEntityDescription.insertNewObject(forEntityName: "User", into: context)
user.setValue(accessToken, forKey: "access_token")
After
swift
import CoreData
import CryptoKit
enum StorageEncryptionError: Error {
case missingCombinedRepresentation
}
func storeToken(
context: NSManagedObjectContext,
accessToken: Data,
databaseKey: SymmetricKey
) throws {
let sealedBox = try AES.GCM.seal(accessToken, using: databaseKey)
guard let encryptedToken = sealedBox.combined else {
throw StorageEncryptionError.missingCombinedRepresentation
}
let user = NSEntityDescription.insertNewObject(
forEntityName: "User", into: context)
user.setValue(encryptedToken, forKey: "access_token")
}
Explanation:
- Before: The authentication token is stored in plaintext in the local database.
- After: Only the combined representation produced by CryptoKit's authenticated AES-GCM encryption is stored. Keep
databaseKeyin a separate secure store such as Keychain, rather than in the database or source code.