Administrative credentials stored in cache memory - Swift

Administrative credentials stored in cache memory - Swift

Need

Secure storage of administrative credentials

Context

  • Usage of Swift for iOS and macOS app development
  • Usage of UIKit for building modern and responsive user interfaces

Description

Non compliant code

        import UIKit

class LoginViewController: UIViewController {
    @IBOutlet weak var usernameField: UITextField!
    @IBOutlet weak var passwordField: UITextField!
    
    @IBAction func loginButtonTapped(_ sender: Any) {
        let username = usernameField.text!
        let password = passwordField.text!
        
        UserDefaults.standard.setValue(username, forKey: "username")
        UserDefaults.standard.setValue(password, forKey: "password")
    }
}
        
        

The above Swift code represents a simple login screen in an iOS application where a user can enter their username and password. When the login button is tapped, the entered username and password are stored in the UserDefaults which is a simple, easy-to-use interface to the user’s default system.

The vulnerability here is that the administrative credentials (username and password) are being stored in UserDefaults. UserDefaults are not encrypted and can be accessed by anyone who has access to the device. This allows for potential attackers to easily retrieve these credentials from the device's cache memory.

Storing sensitive information like usernames and passwords directly into UserDefaults is a bad practice because UserDefaults are not meant for storing sensitive information. They are meant for storing small amounts of data that doesn't need to be secure. Also, UserDefaults are stored in plist files which are easily readable.

This code should be fixed by removing the storage of the username and password from UserDefaults and instead using a secure method for storing these credentials, such as Keychain Services.

Steps

  • Avoid storing sensitive information, such as administrative credentials, in UserDefaults.
  • Use a secure storage mechanism, such as Keychain, to store sensitive information.
  • Encrypt the sensitive information before storing it in the secure storage mechanism.
  • Implement proper access controls to restrict access to the sensitive information.
  • Ensure that the sensitive information is cleared from memory after it is no longer needed.

Compliant code

        import UIKit
import Security

class LoginViewController: UIViewController {
    @IBOutlet weak var usernameField: UITextField!
    @IBOutlet weak var passwordField: UITextField!
    
    @IBAction func loginButtonTapped(_ sender: Any) {
        let username = usernameField.text!
        let password = passwordField.text!
        
        // Store credentials securely in Keychain
        let keychainQuery: [NSString: Any] = [
            kSecClass: kSecClassGenericPassword,
            kSecAttrAccount: username,
            kSecValueData: password.data(using: .utf8)!
        ]
        
        let status = SecItemAdd(keychainQuery as CFDictionary, nil)
        guard status == errSecSuccess else { return }
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        
        // Clear text fields
        usernameField.text = ""
        passwordField.text = ""
    }
}
        
        

The updated code now securely stores the administrative credentials in the Keychain instead of UserDefaults. Keychain is a secure storage mechanism provided by iOS that is designed to keep sensitive data, like user credentials, secure.

In the loginButtonTapped function, we create a dictionary keychainQuery that contains the class of the item we want to add to the Keychain ( kSecClassGenericPassword), the account name ( username), and the password ( password). We then call SecItemAdd to add this new item to the Keychain. If the function returns errSecSuccess, the item was successfully added.

In the viewDidDisappear function, we clear the text fields. This ensures that the sensitive information is cleared from memory after it is no longer needed.

This code does not implement access controls to restrict access to the sensitive information. This would need to be implemented at a higher level, such as requiring the user to authenticate before accessing the view that contains the LoginViewController.

References