M4: Insecure Authentication

M4: Insecure Authentication

Weak authentication schemes allow attackers to bypass authentication or assume other users' identities.

Common Issues:

  • Weak password policies
  • No account lockout mechanisms
  • Insecure password recovery
  • Missing multi-factor authentication
  • Client-side authentication
// Android - Secure authentication implementation
class SecureAuthenticationManager(private val context: Context) {
    
    // VULNERABLE: Weak authentication patterns
    class WeakAuthentication {
        // Bad: Client-side only authentication
        fun authenticateUser(username: String, password: String): Boolean {
            return username == "admin" && password == "password123"
        }
        
        // Bad: Storing passwords in plain text
        fun saveUserCredentials(username: String, password: String) {
            val prefs = context.getSharedPreferences("auth", Context.MODE_PRIVATE)
            prefs.edit()
                .putString("username", username)
                .putString("password", password) // Never store passwords!
                .apply()
        }
    }
    
    // SECURE: Robust authentication system
    class StrongAuthentication(private val context: Context) {
        private val maxLoginAttempts = 5
        private val lockoutDuration = 30 * 60 * 1000L // 30 minutes
        
        suspend fun authenticateUser(username: String, password: String): AuthResult {
            // Check account lockout
            if (isAccountLocked(username)) {
                return AuthResult.AccountLocked
            }
            
            // Validate input
            if (!isValidUsername(username) || !isValidPassword(password)) {
                return AuthResult.InvalidCredentials
            }
            
            // Server-side authentication
            val authRequest = AuthRequest(
                username = username,
                passwordHash = hashPassword(password),
                deviceId = getDeviceId(),
                timestamp = System.currentTimeMillis()
            )
            
            return try {
                val response = secureApiCall("/auth/login", authRequest)
                
                if (response.success) {
                    // Store session securely
                    storeAuthSession(response.sessionToken, response.refreshToken)
                    
                    // Enable biometric for future logins
                    enableBiometricAuth(username)
                    
                    AuthResult.Success(response.sessionToken)
                } else {
                    handleFailedAttempt(username)
                    AuthResult.InvalidCredentials
                }
            } catch (e: Exception) {
                AuthResult.NetworkError
            }
        }
        
        private fun hashPassword(password: String): String {
            // Use Argon2 or similar strong hashing
            return Argon2Factory.create().hash(
                10, // iterations
                65536, // memory
                1, // parallelism
                password.toCharArray()
            )
        }
        
        private suspend fun enableBiometricAuth(username: String) {
            val biometricManager = BiometricManager.from(context)
            
            when (biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG)) {
                BiometricManager.BIOMETRIC_SUCCESS -> {
                    // Generate key requiring biometric auth
                    val keyGenerator = KeyGenerator.getInstance(
                        KeyProperties.KEY_ALGORITHM_AES,
                        "AndroidKeyStore"
                    )
                    
                    val keyGenSpec = KeyGenParameterSpec.Builder(
                        "biometric_key_$username",
                        KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
                    )
                        .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                        .setUserAuthenticationRequired(true)
                        .setInvalidatedByBiometricEnrollment(true)
                        .build()
                    
                    keyGenerator.init(keyGenSpec)
                    keyGenerator.generateKey()
                }
            }
        }
        
        // Implement OAuth 2.0 with PKCE
        fun initiateOAuthFlow(): OAuthRequest {
            val codeVerifier = generateCodeVerifier()
            val codeChallenge = generateCodeChallenge(codeVerifier)
            
            // Store verifier securely
            storeCodeVerifier(codeVerifier)
            
            return OAuthRequest(
                clientId = BuildConfig.OAUTH_CLIENT_ID,
                redirectUri = "app://oauth/callback",
                codeChallenge = codeChallenge,
                codeChallengeMethod = "S256",
                scope = "openid profile email",
                state = generateSecureRandomString()
            )
        }
    }
    
    sealed class AuthResult {
        data class Success(val token: String) : AuthResult()
        object InvalidCredentials : AuthResult()
        object AccountLocked : AuthResult()
        object NetworkError : AuthResult()
    }
}