CWE 287 - Improper Authentication

Disclaimer
  • The code provided is for **educational purposes** only and should not be used in a **production environment** without proper review and testing.

  • The provided code should be regarded as **best practice**. There are also several ways to remediate the Vulnerabilities.

  • The code provided **may contain vulnerabilities** that could be exploited by attackers, and is intended to be used as a learning tool to help improve security awareness and best practices.

  • The mitigations provided are intended to address **specific vulnerabilities** in the code, but may not be effective against all potential attack vectors or scenarios.

  • The code provided is not **guaranteed to be secure or free** from all vulnerabilities, and should be reviewed and tested thoroughly before being used in a production environment.

  • The code provided is **not a substitute for professional security** advice or guidance, and users should consult with a qualified security professional before implementing any security measures.

  • The authors and contributors of the code provided **cannot be held responsible** for any damages or losses resulting from the use of this code.

  • The code provided is provided "as is" without any warranties, express or implied, including but not limited to the implied warranties of merchantability and fitness for a particular purpose.

  • We do not have any sponsors or financial interests in any specific products or services, and the information provided is based solely on our own knowledge and experience.

  • The vulnerable and mitigated code samples provided on our platform are generated with the help of AI and sourced from the internet. We have made every effort to ensure that the code is accurate and up-to-date, but we cannot guarantee its correctness or completeness. If you notice that any of the code samples belong to you and you wish for it to be removed, please contact us and we will take appropriate action. We also apologize for any inconvenience caused and are committed to giving appropriate credit to the respective authors.

About CWE 287

Improper Authentication

This Vulnerability occurs when authentication mechanisms are implemented incorrectly or not used at all, leading to potential security risks and unauthorized access to sensitive information or functionalities.

Impact

  • Unauthorized access

  • Data breaches

  • Privilege escalation

  • Account takeover

  • Identity theft

  • Service disruption

  • Reputation damage

  • Financial losses

Example with Code Explanation

C++

  • Let us consider an example case and understand the CWE 287 with context of Vulnerable code and Mitigated code.

Vulnerable Code

#include <iostream>
#include <string>

bool isAdmin = false;

void authenticateUser(const std::string& username, const std::string& password) {
    if (username == "admin" && password == "secretpassword") {
        isAdmin = true; // Successful authentication
    } else {
        isAdmin = false; // Authentication failed
    }
}

void performAdminAction() {
    if (isAdmin) {
        std::cout << "Performing admin action..." << std::endl;
        // Code to execute the admin action
    } else {
        std::cout << "Access denied. Not authenticated as admin." << std::endl;
        // Code to handle unauthorized access
    }
}

int main() {
    std::string username;
    std::string password;

    std::cout << "Enter username: ";
    std::cin >> username; // Vulnerable function - susceptible to input manipulation

    std::cout << "Enter password: ";
    std::cin >> password; // Vulnerable function - susceptible to input manipulation

    authenticateUser(username, password);

    performAdminAction();

    return 0;
}

The vulnerability lies in the insecure authentication mechanism. The authenticateUser() function is responsible for validating the username and password provided. However, it directly sets the isAdmin flag without any secure authentication checks.

  • Some of the ways the Vulnerable code can be mitigated is:

    • Use Strong Authentication Mechanisms: Implement robust authentication methods, such as password hashing with salt, to protect user credentials. Utilize industry-standard algorithms like bcrypt, Argon2, or PBKDF2.

    • Enforce Password Complexity: Require users to create strong passwords by enforcing complexity requirements, such as a minimum length, a mix of uppercase and lowercase letters, numbers, and special characters.

    • Implement Multi-Factor Authentication (MFA): Use MFA to provide an additional layer of security. This can include methods like SMS verification, email verification, hardware tokens, or biometric authentication.

    • Implement Account Lockout: Enforce account lockout mechanisms that temporarily suspend accounts after a specified number of failed login attempts. This helps protect against brute-force attacks.

    • Implement Secure Session Management: Ensure secure handling of session tokens, including proper generation, storage, transmission, and expiration. Implement mechanisms to prevent session fixation and session hijacking attacks.

Mitigated Code

#include <iostream>
#include <string>
#include <algorithm>
#include <random>
#include <chrono>
#include <iomanip>
#include <limits>

bool isAdmin = false;

// Function to securely compare two strings (to avoid timing attacks)
bool secureCompare(const std::string& a, const std::string& b) {
    if (a.length() != b.length())
        return false;

    int result = 0;
    for (size_t i = 0; i < a.length(); ++i)
        result |= a[i] ^ b[i];

    return result == 0;
}

bool authenticateUser(const std::string& username, const std::string& password) {
    // Simulating secure password storage and retrieval
    std::string storedUsername = "admin";
    std::string storedPasswordHash = "a1f2d4e8c7b6"; // Example stored password hash

    if (secureCompare(username, storedUsername) && bcrypt_verify(password.c_str(), storedPasswordHash.c_str()) == 0) {
        return true; // Successful authentication
    } else {
        return false; // Authentication failed
    }
}

void performAdminAction() {
    if (isAdmin) {
        std::cout << "Performing admin action..." << std::endl;
        // Code to execute the admin action
    } else {
        std::cout << "Access denied. Not authenticated as admin." << std::endl;
        // Code to handle unauthorized access
    }
}

int main() {
    std::string username;
    std::string password;

    std::cout << "Enter username: ";
    std::cin >> username;

    std::cout << "Enter password: ";
    std::cin >> password;

    // Securely hash the password
    std::string hashedPassword = bcrypt_generate_hash(password.c_str(), 10);

    // Clear the original password from memory
    std::fill(password.begin(), password.end(), '\0');

    if (authenticateUser(username, hashedPassword)) {
        std::cout << "Authentication successful!" << std::endl;
        isAdmin = true;
        performAdminAction();
    } else {
        std::cout << "Authentication failed!" << std::endl;
        // Handle failed authentication
    }

    // Clear the hashed password from memory
    std::fill(hashedPassword.begin(), hashedPassword.end(), '\0');

    // Clear the username from memory
    std::fill(username.begin(), username.end(), '\0');

    return 0;
}
  • The mitigated code does the following:

    • Strong Password Storage: The password is hashed using the bcrypt algorithm before being stored. The bcrypt_generate_hash() function is used to securely hash the password, and the bcrypt_verify() function is used to verify the entered password against the stored hash.

    • Secure Password Input: The password is read into a std::string to prevent buffer overflow vulnerabilities. The password is securely cleared from memory using std::fill() to avoid leaving sensitive information behind.

    • Secure Comparison: The secureCompare() function is used to compare the username and password securely, mitigating against timing attacks.

    • Clearing Sensitive Data: After authentication, the hashed password, username, and other sensitive data are securely cleared from memory using std::fill() to minimize the risk of memory attacks.

JAVA

Vulnerable Code

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class InsecureAuthenticationServlet extends HttpServlet {
    private static final String USERNAME = "admin";
    private static final String PASSWORD = "password123";

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        if (username.equals(USERNAME) && password.equals(PASSWORD)) {
            // Authentication successful
            Cookie authCookie = new Cookie("authToken", "1234567890");
            response.addCookie(authCookie);
            response.sendRedirect("/dashboard");
        } else {
            // Authentication failed
            response.sendRedirect("/login?error=1");
        }
    }
}

The code handles a POST request to authenticate a user. It retrieves the values of the username and password parameters from the request. However, the code directly compares these values with the hardcoded username and password stored in the constants USERNAME and PASSWORD. Also, after successful authentication, the code generates an authentication token and stores it in a cookie named "authToken.”

Some of the ways the Vulnerable code can be mitigated is:

  • Secure Password Storage: Instead of storing passwords in plaintext, use a strong hashing algorithm (e.g., bcrypt, Argon2) to securely hash and store passwords. When authenticating users, hash the entered password and compare it with the stored hashed password.

  • Secure Session Management: Rather than relying on a simple authentication token stored in a cookie, use a session management library or framework that handles session creation, storage, and expiration securely. This helps prevent session hijacking and session fixation attacks.

  • Secure Communication: Ensure that the login page and subsequent authentication requests are served over HTTPS. This encrypts the communication between the client and server, protecting sensitive data from interception and tampering.

  • Input Validation and Sanitization: Implement strict input validation and sanitization techniques to prevent common attacks such as SQL injection and cross-site scripting (XSS). Validate and sanitize all user inputs before processing or storing them.

  • Secure Cookie Configuration: When setting cookies, configure them with secure attributes. Set the HttpOnly flag to prevent client-side JavaScript access, and enable the Secure flag to ensure the cookie is only transmitted over HTTPS. Set an appropriate Max-Age or Expires value to control the cookie's lifespan.

  • Implement Multi-Factor Authentication: Consider implementing multi-factor authentication (MFA) to provide an extra layer of security. This can involve methods such as sending a verification code to the user's mobile device or using biometric authentication.

Mitigated Code

import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class SecureAuthenticationServlet extends HttpServlet {
    private static final String USERNAME = "admin";
    private static final String SALT = "randomsalt";

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        if (authenticateUser(username, password)) {
            // Authentication successful
            String authToken = generateAuthToken(username);
            HttpSession session = request.getSession();
            session.setAttribute("authToken", authToken);
            response.sendRedirect("/dashboard");
        } else {
            // Authentication failed
            response.sendRedirect("/login?error=1");
        }
    }

    private boolean authenticateUser(String username, String password) {
        // Fetch the hashed password from the database or storage
        String storedHashedPassword = getStoredHashedPassword(username);

        if (storedHashedPassword == null) {
            return false;
        }

        String hashedPassword = hashPassword(password, SALT);

        // Compare the hashed password with the stored hashed password
        return hashedPassword.equals(storedHashedPassword);
    }

    private String getStoredHashedPassword(String username) {
        // Implement logic to fetch the hashed password from the database or storage
        // Return the stored hashed password for the provided username
        // Return null if the username is not found
        // Example implementation:
        if (username.equals(USERNAME)) {
            return "a7b7b6df62d536fe132c9133d8e57a3b"; // Example hashed password
        } else {
            return null;
        }
    }

    private String hashPassword(String password, String salt) {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            String saltedPassword = password + salt;
            byte[] hashedBytes = md.digest(saltedPassword.getBytes());

            StringBuilder sb = new StringBuilder();
            for (byte hashedByte : hashedBytes) {
                sb.append(Integer.toString((hashedByte & 0xff) + 0x100, 16).substring(1));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    private String generateAuthToken(String username) {
        // Implement logic to generate a secure authentication token
        // Return the generated token
        // Example implementation:
        return "1234567890";
    }
}

The Mitigated code does the following:

  • The password is no longer stored in plaintext. Instead, it is securely hashed with a salt value before being stored. The hashPassword method hashes the password using the SHA-256 algorithm with a salt value.

  • The authenticateUser method compares the entered password by hashing it with the same salt used during registration and then compares the hashed password with the stored hashed password.

  • The authToken is now stored in the user's session using HttpSession. The session provides a secure mechanism to store and manage the authentication token.

  • The getStoredHashedPassword method is a placeholder for fetching the hashed password from a database or storage. In a real-world scenario, you would replace this method with appropriate database access code.

Python

Vulnerable Code

def login(username, password):
    if username == "admin" and password == "password":
        print("Login successful!")
        # Proceed with sensitive operations
    else:
        print("Login failed!")

username = input("Username: ")
password = input("Password: ")
login(username, password)

The login function accepts a username and password as input. However, it doesn't perform any proper authentication. It simply checks if the provided username is "admin" and the password is "password". If the conditions are met, it prints "Login successful!" and proceeds with sensitive operations. Otherwise, it prints "Login failed!". An attacker can easily bypass the login process by guessing or brute-forcing the username and password combination since the checks are very weak.

Some of the ways the Vulnerable code can be mitigated is:

  • Use Strong Password Hashing: Properly implemented strong password hashing, such as bcrypt, makes it extremely difficult for attackers to crack passwords, even if they gain access to the hashed passwords.

  • Implement Salting: Salting adds uniqueness to each password hash, making precomputed tables (rainbow tables) ineffective and increasing the time and effort required for brute-force attacks.

  • Enforce Password Complexity: Requiring complex passwords mitigates the risk of easy guessing or brute-forcing of weak passwords.

  • Limit Login Attempts: By limiting the number of failed login attempts, you can deter brute-force attacks, reducing the likelihood of an attacker guessing the correct password.

  • Implement Account Lockout: Account lockout after multiple failed login attempts provides an additional layer of defense against brute-force attacks.

  • Use Multi-Factor Authentication (MFA): MFA adds an extra layer of security by requiring additional factors for authentication, reducing the impact of stolen passwords.

  • Protect Passwords in Transit and Storage: Secure transmission and storage of passwords with encryption and proper access controls mitigate the risk of interception or unauthorized access.

Mitigated Code

import bcrypt

# Sample hashed password for "admin"
hashed_password = b'$2b$12$u0FPP8K9ZCk1Z6WHYwFZ2.P6n..PjMq/Xr5uCI/r28nsvBzPG6KU6'

def login(username, password):
    stored_password = hashed_password  # Retrieve the stored hashed password from a secure database
    if bcrypt.checkpw(password.encode('utf-8'), stored_password):
        print("Login successful!")
        # Proceed with sensitive operations
    else:
        print("Login failed!")

def register(username, password):
    salt = bcrypt.gensalt()
    hashed_password = bcrypt.hashpw(password.encode('utf-8'), salt)
    # Store the hashed_password securely in a database

username = input("Username: ")
password = input("Password: ")
login(username, password)

The Mitigated code does the following:

  • Strong Password Hashing: We use the bcrypt library to securely hash and verify passwords.

  1. Salted Hashing: Each password is combined with a unique salt before hashing, adding an additional layer of security.

  2. Secure Storage: We assume that the hashed password is retrieved securely from a database and properly protected.

  3. User Registration: We have not included the complete registration process, but you can incorporate the register function to securely hash and store user passwords during registration.

References

Authentication - OWASP Cheat Sheet Series

A07 Identification and Authentication Failures - OWASP Top 10:2021

Comprehensive Guide on Broken Authentication & Session Management - Hacking Articles

Authentication vulnerabilities | Web Security Academy

Last updated

Was this helpful?