Sensitive information in source code - Credentials - Swift

Sensitive information in source code - Credentials - Swift

Need

Protection of sensitive information in source code

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 {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        let username = "admin"
        let password = "123456"
        let email = "admin@example.com"
        let api_key = "abcd1234"
        
        // Code to use these credentials
    }
}
        
        

In the above code snippet, the sensitive information (username, password, email, API key) is hard-coded directly into the source code. This is a significant security vulnerability because anyone who has access to this code can see and use these credentials.

If this code is part of a version control system like Git, then these credentials are also part of the version history. Even if the credentials are removed from the code in a later commit, they can still be viewed in the commit history.

Moreover, hard-coding credentials like this makes it difficult to change them. If the password needs to be changed, for example, a new version of the app needs to be released.

The credentials are also the same for every instance of the app, which makes it impossible to limit access on a per-user basis.

Finally, if the API key is compromised, it can be used to impersonate the app and misuse its privileges.

In a real-world application, this could lead to unauthorized access to sensitive data, identity theft, and other serious security breaches.

Steps

  • Remove sensitive information from the source code.
  • Store sensitive information in a secure location, such as a configuration file or a key management system.
  • Use environment variables or secure storage mechanisms to access sensitive information at runtime.
  • Implement proper access controls and permissions to restrict access to sensitive information.
  • Regularly review and update the stored sensitive information to ensure it is up to date and secure.

Compliant code

        import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        
        guard let username = ProcessInfo.processInfo.environment["USERNAME"],
              let password = ProcessInfo.processInfo.environment["PASSWORD"],
              let email = ProcessInfo.processInfo.environment["EMAIL"],
              let api_key = ProcessInfo.processInfo.environment["API_KEY"] else {
            fatalError("Missing environment variables")
        }
        
        // Code to use these credentials
    }
}
        
        

The updated code no longer stores sensitive information directly in the source code. Instead, it retrieves these values from environment variables at runtime. This approach is more secure because the sensitive information is not exposed in the source code and can be managed separately, for example, in a secure configuration file or a key management system.

The ProcessInfo.processInfo.environment is a dictionary that contains the environment variables. We use it to retrieve the values of the USERNAME, PASSWORD, EMAIL, and API_KEY environment variables. If any of these variables are not set, the guard let statement will fail, and the program will terminate with a fatalError.

Remember to set these environment variables in the secure storage of your choice before running the application. Also, ensure that proper access controls and permissions are in place to restrict access to these environment variables.

Regularly review and update the stored sensitive information to ensure it is up to date and secure.

References