Security controls bypass or absence - Swift

Security controls bypass or absence - Swift

Need

Implementation of robust security controls

Context

  • Usage of Swift for iOS and macOS app development
  • Usage of UIKit for building modern and responsive user interfaces
  • Usage of LocalAuthentication for implementing local device authentication

Description

Non compliant code

        import UIKit
import LocalAuthentication

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func authenticateUser(_ sender: Any) {
        let context = LAContext()
        var error: NSError?
        
        if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
            let reason = "Identify yourself!"
            
            context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) {
                [unowned self] success, authenticationError in
                
                DispatchQueue.main.async {
                    if success {
                        self.runSecretCode()
                    } else {
                        // Fall back to asking for a password.
                    }
                }
            }
        } else {
            // Device does not support biometric authentication.
        }
    }
    
    func runSecretCode() {
        // Code to run after successful authentication
    }
}
        
        

The above Swift code is for a view controller in an iOS application that tries to authenticate the user using biometric authentication (Touch ID or Face ID). If the biometric authentication is successful, it runs some secret code.

The vulnerability here lies in the fact that there is no fallback mechanism in place if the biometric authentication fails. An attacker could potentially bypass the biometric authentication step by exploiting this vulnerability, and gain unauthorized access to the secret code.

In the authenticateUser function, the app checks if the device can evaluate a biometric policy. If it can, it requests biometric authentication. If the authentication is successful, the runSecretCode function is called. However, if the authentication fails, there is no code to handle this scenario. This could allow an attacker to bypass the biometric authentication.

Moreover, the runSecretCode function is not secured and can be accessed from outside the class. This could allow an attacker to run this function without going through the authentication process.

Steps

  • Implement additional security controls to prevent bypassing.
  • Use secure authentication methods instead of relying solely on biometric authentication.
  • Handle authentication failures properly and provide appropriate error messages.
  • Consider implementing multi-factor authentication for enhanced security.
  • Regularly update and patch the application to address any security vulnerabilities.

Compliant code

        import UIKit
import LocalAuthentication

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func authenticateUser(_ sender: Any) {
        let context = LAContext()
        var error: NSError?
        
        if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
            let reason = "Identify yourself!"
            
            context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) {
                [unowned self] success, authenticationError in
                
                DispatchQueue.main.async {
                    if success {
                        self.runSecretCode()
                    } else {
                        // Handle authentication failure
                        self.handleAuthenticationFailure()
                    }
                }
            }
        } else {
            // Device does not support biometric authentication.
            // Fall back to password authentication
            self.passwordAuthentication()
        }
    }
    
    func runSecretCode() {
        // Code to run after successful authentication
    }
    
    func handleAuthenticationFailure() {
        // Handle authentication failure and provide appropriate error message
    }
    
    func passwordAuthentication() {
        // Implement password authentication
    }
}
        
        

The updated code includes additional security controls to prevent bypassing. Instead of solely relying on biometric authentication, the system now falls back to password authentication if the device does not support biometric authentication or if biometric authentication fails.

The handleAuthenticationFailure() function is called when biometric authentication fails. This function should handle the failure appropriately and provide a suitable error message to the user.

The passwordAuthentication() function is called when the device does not support biometric authentication. This function should implement a secure password authentication method.

These changes enhance the security of the application by implementing multi-factor authentication and handling authentication failures properly. Regular updates and patches should also be applied to the application to address any future security vulnerabilities.

References