Non-encrypted confidential information - Base 64 - Swift

Non-encrypted confidential information - Base 64 - Swift

Need

Secure storage of confidential information

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 ViewController: UIViewController {

    let username: String = "admin"
    let password: String = "password123"

    override func viewDidLoad() {
        super.viewDidLoad()
        let credentials = "\\(username):\\(password)"
        let base64Credentials = Data(credentials.utf8).base64EncodedString()
        print("Base64 encoded credentials: \\(base64Credentials)")
    }
}
        
        

In the Swift code above, the username and password are hardcoded directly into the source code. These credentials are then concatenated into a single string with a colon (:) separator. This string is then encoded into Base64 format using the base64EncodedString() method of the Data class. The encoded credentials are then printed out to the console.

This is a vulnerability because anyone who has access to the source code can easily decode the Base64 string to reveal the original credentials. In addition, if anyone is able to intercept the console logs (e.g. if they are stored in a log file or sent over a network), they can also decode the Base64 string to get the credentials.

It is a bad practice to store sensitive information like usernames and passwords directly in the source code. It is even worse to encode them in Base64 format, as Base64 is not an encryption algorithm and can be easily decoded.

This vulnerability can be exploited to gain unauthorized access to the system that these credentials are supposed to protect. This can lead to data breaches, unauthorized actions on the system, and other security issues.

Steps

  • Remove the hard-coded username and password from the code.
  • Store the credentials securely, such as in the Keychain or using secure storage mechanisms provided by the platform.
  • Use encryption to protect the confidential information, such as using HTTPS for network communication.
  • Avoid storing sensitive information in plain text or using weak encryption algorithms.
  • Implement proper authentication mechanisms to ensure only authorized users can access the confidential information.
  • Regularly review and update the security measures in place to protect the confidential information.

Compliant code

        import UIKit
import Security

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        saveCredentials(username: "admin", password: "password123")
        if let loadedCredentials = loadCredentials() {
            print("Loaded credentials: \\(loadedCredentials)")
        }
    }
    
    func saveCredentials(username: String, password: String) {
        let credentials = "\\(username):\\(password)"
        let credentialsData = Data(credentials.utf8)
        
        let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
                                    kSecAttrAccount as String: "userAccount",
                                    kSecValueData as String: credentialsData]
        
        let status = SecItemAdd(query as CFDictionary, nil)
        guard status == errSecSuccess else { return }
    }
    
    func loadCredentials() -> String? {
        let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
                                    kSecAttrAccount as String: "userAccount",
                                    kSecReturnData as String: kCFBooleanTrue!,
                                    kSecMatchLimit as String: kSecMatchLimitOne]
        
        var dataTypeRef: AnyObject?
        let status: OSStatus = SecItemCopyMatching(query as CFDictionary, &dataTypeRef)
        
        if status == errSecSuccess {
            if let retrievedData = dataTypeRef as? Data,
               let credentials = String(data: retrievedData, encoding: .utf8) {
                return credentials
            }
        }
        return nil
    }
}
        
        

The updated code now securely stores the credentials in the iOS Keychain, which is a secure storage provided by the platform. The saveCredentials(username:password:) function is used to save the credentials to the Keychain. It first combines the username and password into a single string, then converts this string into a Data object. This Data object is then stored in the Keychain with the account name "userAccount".

The loadCredentials() function is used to retrieve the credentials from the Keychain. It queries the Keychain for the data associated with the account name "userAccount". If the query is successful, it retrieves the data, converts it back into a string, and returns this string.

This approach ensures that the credentials are not stored in plain text in the source code, and are instead stored securely in the Keychain. It also ensures that the credentials are not printed to the console in plain text, further enhancing the security of the application.

References