Weak Authentication

Description

Weak Authentication occurs when a product implements an authentication mechanism to restrict access to specific users or identities, but fails to sufficiently verify that the claimed identity is correct. Attackers may be able to bypass weak authentication faster and/or with less effort than expected. Weak authentication can result from various issues including insufficient challenge strength, predictable authentication tokens, single-factor authentication, improper credential validation, or authentication bypass vulnerabilities.

Risk

Weak authentication has severe implications. Unauthorized access to protected resources. Identity impersonation. Privilege escalation. Data exposure. Account takeover. System compromise. Lateral movement in networks. Compliance violations. Reputational damage. High likelihood when authentication mechanisms are poorly designed or implemented.

Solution

Implement strong multi-factor authentication during architecture and design phase. Use industry-standard authentication protocols. Enforce strong password policies during implementation phase. Implement account lockout mechanisms. Use cryptographically secure session tokens. Employ proper credential storage with strong hashing. Validate all authentication inputs thoroughly.

Common Consequences

ImpactDetails
ConfidentialityScope: Confidentiality

Exposure of sensitive information to unauthorized actors through authentication bypass.
IntegrityScope: Integrity

Attackers may impersonate legitimate users and modify protected data.
Access ControlScope: Access Control

Potential execution of unauthorized operations and privilege escalation.

Example Code

Vulnerable Code

# Vulnerable: Weak authentication implementations

import hashlib
import time
import random

# VULNERABLE: Timestamp-based authentication
class VulnerableTimestampAuth:
    def authenticate(self, user_id, timestamp_token):
        # VULNERABLE: Token is just current timestamp
        current_time = int(time.time())

        # VULNERABLE: Large time window (5 minutes)
        if abs(current_time - int(timestamp_token)) < 300:
            return True  # Authenticated

        # Attack: Attacker can predict/calculate valid tokens
        return False

# VULNERABLE: Weak session token generation
def vulnerable_generate_session():
    # VULNERABLE: Predictable random seed
    random.seed(int(time.time()))

    # VULNERABLE: Simple random number as token
    return str(random.randint(0, 999999))

# VULNERABLE: MD5 password hashing (fast, vulnerable to rainbow tables)
def vulnerable_hash_password(password):
    # VULNERABLE: MD5 is cryptographically broken
    return hashlib.md5(password.encode()).hexdigest()

# VULNERABLE: No salt in password hash
def vulnerable_verify_password(password, stored_hash):
    # VULNERABLE: Direct comparison without salt
    return vulnerable_hash_password(password) == stored_hash

# VULNERABLE: Basic authentication without rate limiting
class VulnerableLoginHandler:
    def __init__(self):
        self.users = {}  # username -> password_hash

    def login(self, username, password):
        # VULNERABLE: No rate limiting - allows brute force
        # VULNERABLE: No account lockout
        if username in self.users:
            if vulnerable_verify_password(password, self.users[username]):
                return vulnerable_generate_session()

        return None  # Login failed
// Vulnerable: Java weak authentication patterns

import java.util.Base64;
import java.security.MessageDigest;

public class VulnerableAuth {

    // VULNERABLE: Basic Auth without proper validation
    public boolean vulnerableBasicAuth(String authHeader) {
        if (authHeader == null || !authHeader.startsWith("Basic ")) {
            return false;
        }

        // VULNERABLE: Base64 is encoding, not encryption
        String credentials = new String(
            Base64.getDecoder().decode(authHeader.substring(6))
        );

        String[] parts = credentials.split(":");
        String username = parts[0];
        String password = parts[1];

        // VULNERABLE: Hardcoded credentials
        if ("admin".equals(username) && "admin123".equals(password)) {
            return true;
        }

        return false;
    }

    // VULNERABLE: Weak password verification
    public boolean vulnerablePasswordCheck(String input, String stored) {
        // VULNERABLE: String comparison vulnerable to timing attacks
        return input.equals(stored);
    }

    // VULNERABLE: Predictable session ID
    public String vulnerableGenerateSession(String username) {
        // VULNERABLE: Predictable session format
        long timestamp = System.currentTimeMillis();
        return username + "_" + timestamp;
    }

    // VULNERABLE: Client-side authentication reliance
    public boolean vulnerableTokenAuth(String token) {
        // VULNERABLE: Only checks if token exists, not validity
        return token != null && token.length() > 0;
    }

    // VULNERABLE: Security question authentication
    public boolean vulnerableSecurityQuestion(String answer, String stored) {
        // VULNERABLE: Case-insensitive comparison reduces entropy
        return answer.equalsIgnoreCase(stored);
        // Attack: "What is your pet's name?" - guessable
    }
}
// Vulnerable: JavaScript weak authentication

// VULNERABLE: Client-side authentication check
function vulnerableClientAuth(password) {
    // VULNERABLE: Password checked in client-side JavaScript
    const correctPassword = "secret123";  // Exposed in source

    if (password === correctPassword) {
        localStorage.setItem('authenticated', 'true');
        return true;
    }
    return false;
}

// VULNERABLE: Weak JWT validation
function vulnerableJWTValidation(token) {
    // VULNERABLE: No signature verification
    try {
        const parts = token.split('.');
        const payload = JSON.parse(atob(parts[1]));

        // VULNERABLE: Only checks expiration, not signature
        if (payload.exp > Date.now() / 1000) {
            return payload;
        }
    } catch (e) {
        return null;
    }
    return null;
}

// VULNERABLE: Cookie-based auth without security flags
function vulnerableSetAuthCookie(userId) {
    // VULNERABLE: Missing HttpOnly, Secure, SameSite flags
    document.cookie = `auth=${userId}; path=/`;

    // Attack: XSS can steal this cookie
}

// VULNERABLE: Predictable password reset token
function vulnerableGenerateResetToken(email) {
    // VULNERABLE: Token based on email and time
    const timestamp = Date.now();
    return btoa(email + ':' + timestamp);

    // Attack: Attacker can generate valid tokens
}

Fixed Code

# Fixed: Strong authentication implementations

import secrets
import hashlib
import time
from datetime import datetime, timedelta
import bcrypt
import pyotp
from collections import defaultdict

# FIXED: Strong session token generation
def safe_generate_session():
    # FIXED: Cryptographically secure random token
    return secrets.token_urlsafe(32)

# FIXED: Secure password hashing with bcrypt
def safe_hash_password(password):
    # FIXED: bcrypt with automatic salt
    salt = bcrypt.gensalt(rounds=12)
    return bcrypt.hashpw(password.encode(), salt)

def safe_verify_password(password, stored_hash):
    # FIXED: Constant-time comparison built into bcrypt
    return bcrypt.checkpw(password.encode(), stored_hash)

# FIXED: Rate limiting and account lockout
class SafeLoginHandler:
    def __init__(self):
        self.users = {}  # username -> password_hash
        self.failed_attempts = defaultdict(list)
        self.locked_accounts = {}

    # FIXED: Constants for rate limiting
    MAX_ATTEMPTS = 5
    LOCKOUT_DURATION = timedelta(minutes=15)
    ATTEMPT_WINDOW = timedelta(minutes=5)

    def _is_locked(self, username):
        """FIXED: Check if account is locked."""
        if username in self.locked_accounts:
            lock_time = self.locked_accounts[username]
            if datetime.now() < lock_time + self.LOCKOUT_DURATION:
                return True
            else:
                del self.locked_accounts[username]
        return False

    def _record_failed_attempt(self, username):
        """FIXED: Record failed login attempt."""
        now = datetime.now()
        attempts = self.failed_attempts[username]

        # Remove old attempts outside window
        attempts[:] = [t for t in attempts
                      if now - t < self.ATTEMPT_WINDOW]

        attempts.append(now)

        # FIXED: Lock account after max attempts
        if len(attempts) >= self.MAX_ATTEMPTS:
            self.locked_accounts[username] = now

    def login(self, username, password):
        # FIXED: Check for account lockout
        if self._is_locked(username):
            raise AuthenticationError("Account locked. Try again later.")

        if username not in self.users:
            # FIXED: Constant time to prevent user enumeration
            bcrypt.checkpw(b"dummy", bcrypt.gensalt())
            self._record_failed_attempt(username)
            return None

        if safe_verify_password(password, self.users[username]):
            # FIXED: Clear failed attempts on success
            self.failed_attempts[username] = []
            return safe_generate_session()
        else:
            self._record_failed_attempt(username)
            return None

# FIXED: Multi-factor authentication
class MFAHandler:
    def __init__(self):
        self.user_secrets = {}  # username -> TOTP secret

    def setup_mfa(self, username):
        """FIXED: Generate TOTP secret for user."""
        secret = pyotp.random_base32()
        self.user_secrets[username] = secret
        return secret

    def verify_mfa(self, username, code):
        """FIXED: Verify TOTP code."""
        if username not in self.user_secrets:
            return False

        totp = pyotp.TOTP(self.user_secrets[username])
        # FIXED: Verify with small time window
        return totp.verify(code, valid_window=1)

    def full_login(self, username, password, mfa_code):
        """FIXED: Two-factor authentication."""
        # First factor: password
        if not safe_verify_password(password, self.get_password_hash(username)):
            return None

        # FIXED: Second factor: TOTP
        if not self.verify_mfa(username, mfa_code):
            return None

        return safe_generate_session()
// Fixed: Java secure authentication

import java.security.SecureRandom;
import java.security.MessageDigest;
import java.util.Base64;
import java.util.Arrays;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import io.jsonwebtoken.*;

public class SecureAuth {

    private static final SecureRandom SECURE_RANDOM = new SecureRandom();
    private static final int ITERATIONS = 100000;
    private static final int KEY_LENGTH = 256;

    // FIXED: Secure password hashing with PBKDF2
    public String safeHashPassword(String password) throws Exception {
        byte[] salt = new byte[16];
        SECURE_RANDOM.nextBytes(salt);

        PBEKeySpec spec = new PBEKeySpec(
            password.toCharArray(), salt, ITERATIONS, KEY_LENGTH
        );
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        byte[] hash = factory.generateSecret(spec).getEncoded();

        // FIXED: Store salt with hash
        return Base64.getEncoder().encodeToString(salt) + ":" +
               Base64.getEncoder().encodeToString(hash);
    }

    // FIXED: Constant-time password verification
    public boolean safeVerifyPassword(String password, String stored) throws Exception {
        String[] parts = stored.split(":");
        byte[] salt = Base64.getDecoder().decode(parts[0]);
        byte[] expectedHash = Base64.getDecoder().decode(parts[1]);

        PBEKeySpec spec = new PBEKeySpec(
            password.toCharArray(), salt, ITERATIONS, KEY_LENGTH
        );
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        byte[] actualHash = factory.generateSecret(spec).getEncoded();

        // FIXED: Constant-time comparison
        return MessageDigest.isEqual(expectedHash, actualHash);
    }

    // FIXED: Cryptographically secure session ID
    public String safeGenerateSession() {
        byte[] bytes = new byte[32];
        SECURE_RANDOM.nextBytes(bytes);
        return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
    }

    // FIXED: Proper JWT validation
    public Claims safeValidateJWT(String token, String secretKey) {
        try {
            // FIXED: Full signature verification
            return Jwts.parserBuilder()
                .setSigningKey(secretKey.getBytes())
                .build()
                .parseClaimsJws(token)
                .getBody();
        } catch (JwtException e) {
            return null;  // Invalid token
        }
    }

    // FIXED: Secure token generation for password reset
    public String safeGenerateResetToken() {
        byte[] bytes = new byte[32];
        SECURE_RANDOM.nextBytes(bytes);
        return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
    }
}
// Fixed: JavaScript secure authentication

const crypto = require('crypto');
const jwt = require('jsonwebtoken');

// FIXED: Server-side authentication only
// Never check credentials in client-side code

// FIXED: Secure session token generation
function safeGenerateSession() {
    // FIXED: Cryptographically secure random bytes
    return crypto.randomBytes(32).toString('base64url');
}

// FIXED: Proper JWT validation
function safeJWTValidation(token, secretKey) {
    try {
        // FIXED: Full verification including signature
        const payload = jwt.verify(token, secretKey, {
            algorithms: ['HS256'],  // FIXED: Specify algorithm
            complete: true
        });

        return payload;
    } catch (error) {
        // FIXED: Log failed validation attempts
        console.error('JWT validation failed:', error.message);
        return null;
    }
}

// FIXED: Secure cookie settings
function safeSetAuthCookie(res, token) {
    res.cookie('auth', token, {
        httpOnly: true,     // FIXED: Not accessible to JavaScript
        secure: true,       // FIXED: Only sent over HTTPS
        sameSite: 'strict', // FIXED: Prevent CSRF
        maxAge: 3600000,    // 1 hour
        path: '/'
    });
}

// FIXED: Cryptographically secure reset token
function safeGenerateResetToken() {
    // FIXED: Unpredictable token
    return crypto.randomBytes(32).toString('hex');
}

// FIXED: Rate limiting middleware
const rateLimit = require('express-rate-limit');

const loginLimiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15 minutes
    max: 5, // FIXED: Limit each IP to 5 requests per window
    message: 'Too many login attempts, please try again later',
    standardHeaders: true,
    legacyHeaders: false,
});

// FIXED: Constant-time comparison for tokens
function safeCompareTokens(a, b) {
    if (typeof a !== 'string' || typeof b !== 'string') {
        return false;
    }
    // FIXED: Timing-safe comparison
    return crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b));
}

CVE Examples

  • CVE-2024-48445: Weak timestamp-based authentication allowing authentication bypass.
  • CVE-2020-8994: UART interface using empty root passwords.
  • CVE-2022-29965: Deterministic utility password generation enabling credential prediction.

  • CWE-287: Improper Authentication (parent)
  • CWE-289: Authentication Bypass by Alternate Name (child)
  • CWE-290: Authentication Bypass by Spoofing (child)
  • CWE-308: Use of Single-factor Authentication (child)
  • CWE-309: Use of Password System for Primary Authentication (child)

References

  1. MITRE Corporation. "CWE-1390: Weak Authentication." https://cwe.mitre.org/data/definitions/1390.html
  2. OWASP. "Authentication Cheat Sheet"
  3. NIST SP 800-63B. "Digital Identity Guidelines: Authentication and Lifecycle Management"