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()
}
}