CWE 798 - Use of Hard-Coded Credentials
About CWE 798
Use of Hard-coded Credentials
This Vulnerability occurs when software systems that involve the use of credentials (such as usernames and passwords) that are hard-coded
directly into the source code or configuration files of an application.
What is Inbound/Outbound Variant?
Inbound use of hard-coded credentials involves using hard-coded credentials to authenticate incoming requests or connections to the application.
For example, let's say you have a web application that requires users to enter a username and password to log in. In this scenario, if the application's source code contains hard-coded credentials that are used to authenticate the incoming user requests, it would be an example of inbound use of hard-coded credentials.
Outbound use of hard-coded credentials involves using hard-coded credentials to authenticate the application itself when it interacts with external systems or services.
For Example, consider a software application that needs to connect to a database for retrieving or storing data. If the application's code contains hard-coded credentials that are used to authenticate the application when establishing the connection to the database, it would be an example of outbound use of hard-coded credentials.
Impact
Unauthorized Access
Credential Exposure
Lack of Accountability
Difficulty in Credential Management
Compliance Violations
Example with Code Explanation:
Let us consider an example case and understand the CWE 798 with context of Vulnerable code and Mitigated code.
C
C
Vulnerable Code
#include <stdio.h>
#include <string.h>
void authenticate(char* username, char* password) {
char validUsername[] = "admin";
char validPassword[] = "password123";
if (strcmp(username, validUsername) == 0 && strcmp(password, validPassword) == 0) {
printf("Authentication successful.\n");
} else {
printf("Authentication failed.\n");
}
}
int main() {
char username[] = "admin";
char password[] = "password123";
authenticate(username, password);
return 0;
}
In this code, the authenticate
function compares the provided username
and password
with hard-coded credentials (validUsername
and validPassword
). If the comparison succeeds, it prints Authentication successful
, indicating a successful login. Otherwise, it prints Authentication failed.
This approach is vulnerable because the valid credentials are hard-coded
directly into the source code. If an attacker gains access to the code, they can easily extract the credentials and potentially gain unauthorized access to the system.
Some of the ways the Vulnerable code can be mitigated is:
Use Credential Storage Mechanisms:
Instead of hard-coding credentials directly in the code or configuration files, use secure storage mechanisms such as encrypted files, secure key stores, or dedicated credential management systems. This helps protect the credentials from unauthorized access and reduces the risk of exposure.Externalize Credentials:
Store credentials separately from the application code. Use external configuration files or environment variables to provide credentials at runtime. This separation allows for easier credential management, reduces the risk of accidental exposure, and facilitates secure deployment and configuration management.Employ Encryption or Hashing:
If credentials need to be stored within the application, consider using strong encryption or hashing algorithms to protect them. This adds an additional layer of security and makes it harder for attackers to extract the original credentials even if they gain access to the code.Implement Credential Rotation:
Regularly rotate credentials, especially for sensitive accounts or high-value systems. Periodic rotation of credentials reduces the window of opportunity for attackers and limits the potential impact of a compromised credential.Use Token-based Authentication:
Instead of using traditional username/password combinations, consider implementing token-based authentication mechanisms such as JSON Web Tokens (JWT) or OAuth. These mechanisms eliminate the need for hard-coded credentials and provide more secure and flexible authentication options.Employ Secure Key Management:
If using API keys, access tokens, or other forms of credentials, employ secure key management practices. This includes securely generating, distributing, and revoking keys, as well as implementing appropriate access controls and auditing mechanisms.
Mitigated Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
// Simulating retrieval of credentials from a secure configuration file or external source
void retrieveCredentials(char* username, char* password) {
// Retrieve the credentials from a secure storage location or external service
// For demonstration purposes, assume retrieval logic from a secure source
// Example: Retrieval from an encrypted configuration file using SSL/TLS
SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());
if (ctx == NULL) {
printf("Error: Unable to create SSL context.\n");
exit(1);
}
// Load the trust store
if (!SSL_CTX_load_verify_locations(ctx, "truststore.pem", NULL)) {
printf("Error: Unable to load trust store.\n");
exit(1);
}
// Create an SSL connection
BIO* bio = BIO_new_ssl_connect(ctx);
if (bio == NULL) {
printf("Error: Unable to create SSL connection.\n");
exit(1);
}
// Connect to the configuration file server
BIO_set_conn_hostname(bio, "config.example.com:443");
// Verify the server certificate
SSL* ssl;
BIO_get_ssl(bio, &ssl);
if (SSL_get_verify_result(ssl) != X509_V_OK) {
printf("Error: Server certificate verification failed.\n");
exit(1);
}
// Read the encrypted credentials from the configuration file
char encryptedCredentials[64];
int len = BIO_read(bio, encryptedCredentials, sizeof(encryptedCredentials));
if (len <= 0) {
printf("Error: Unable to read encrypted credentials.\n");
exit(1);
}
// Decrypt the credentials using a symmetric key
// For demonstration purposes, assume decryption logic using a symmetric key
// ...
// Parse the decrypted credentials into username and password
if (sscanf(decryptedCredentials, "%s %s", username, password) != 2) {
printf("Error: Invalid credential format.\n");
exit(1);
}
// Free the SSL resources
BIO_free_all(bio);
SSL_CTX_free(ctx);
}
// Compare two strings in constant time to prevent timing attacks
int constant_time_compare(const char* a, const char* b) {
size_t len_a = strlen(a);
size_t len_b = strlen(b);
if (len_a != len_b) {
return 0;
}
unsigned char result = 0;
for (size_t i = 0; i < len_a; i++) {
result |= a[i] ^ b[i];
}
return result == 0;
}
void authenticate(char* username, char* password) {
// Perform authentication logic
// For demonstration purposes, compare with retrieved credentials
char retrievedUsername[32];
char retrievedPassword[32];
// Retrieve the hashed password using the username as a key
retrieveCredentials(retrievedUsername, retrievedPassword);
// Hash the input password using the same algorithm and salt as the retrieved password
char hashedPassword[32];
EVP_MD_CTX* mdctx = EVP_MD_CTX_new();
if (mdctx == NULL) {
printf("Error: Unable to create hash context.\n");
exit(1);
}
if (!EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL)) {
printf("Error: Unable to initialize hash function.\n");
exit(1);
}
// Assume a fixed salt for demonstration purposes
unsigned char salt[] = "1234567890abcdef";
if (!EVP_DigestUpdate(mdctx, salt, sizeof(salt))) {
printf("Error: Unable to update hash with salt.\n");
exit(1);
}
if (!EVP_DigestUpdate(mdctx, password, strlen(password))) {
printf("Error: Unable to update hash with password.\n");
exit(1);
}
unsigned int len;
unsigned char digest[EVP_MAX_MD_SIZE];
if (!EVP_DigestFinal_ex(mdctx, digest, &len)) {
printf("Error: Unable to finalize hash.\n");
exit(1);
}
EVP_MD_CTX_free(mdctx);
// Convert the digest to a hex string
for (unsigned int i = 0; i < len; i++) {
sprintf(hashedPassword + (i * 2), "%02x", digest[i]);
}
hashedPassword[len * 2] = '\0';
// Compare the input username and hashed password with the retrieved ones in constant time
if (constant_time_compare(username, retrievedUsername) && constant_time_compare(hashedPassword, retrievedPassword)) {
printf("Authentication successful.\n");
} else {
printf("Authentication failed.\n");
}
}
int main() {
char username[32];
char password[32];
retrieveCredentials(username, password);
authenticate(username, password);
// Clear credentials from memory
memset(username, 0, sizeof(username));
memset(password, 0, sizeof(password));
return 0;
}
The Mitigated code does the following:
Retrieval of credentials:
The mitigated code simulates retrieving credentials from asecure configuration file or external source
. It uses SSL/TLS to establish a secure connection, loads a trust store, verifies the server certificate, and reads the encrypted credentials from the configuration file. The actual retrieval logic may vary depending on the implementation.Encryption and decryption:
The mitigated code includes encryption and decryption mechanisms to protect the credentials stored in the configuration file. It assumes a symmetric key for decryption, although the actual implementation may use a more secure encryption scheme.Hashing and constant-time comparison:
The mitigated code hashes the input password using a cryptographic hash function (SHA-256) and a salt value. It then compares the hashed password and username with the retrieved values using a constant-time comparison function. This prevents attackers from exploiting timing attacks to gain information about the credentials.Secure memory handling:
The mitigated code clears the credentials from memory usingmemset
after authentication to minimize the risk of the sensitive data being accessed by other processes or attackers.
Java
Java
Vulnerable Code
The below Vulnerable and Mitgated code focuses on Inbound Authentication.
import java.util.Scanner;
public class VulnerableCode {
// Simulating hard-coded default credentials for first time logins
private static final String DEFAULT_USERNAME = "admin";
private static final String DEFAULT_PASSWORD = "password123";
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Assume credentials are obtained securely at runtime
// For demonstration purposes, use hard-coded values
String username = "admin";
String password = "password123";
authenticate(username, password);
// Clear credentials from memory
username = null;
password = null;
scanner.close();
}
public static void authenticate(String username, String password) {
// Perform authentication logic
// For demonstration purposes, compare with default credentials
if (username.equals(DEFAULT_USERNAME) && password.equals(DEFAULT_PASSWORD)) {
System.out.println("Authentication successful.");
} else {
System.out.println("Authentication failed.");
}
}
}
The code is Vulnerable, because it uses hard-coded default credentials for first time logins. The default username and password are stored in plain text in the DEFAULT_USERNAME
and DEFAULT_PASSWORD
constants and can be easily extracted by an attacker. This can allow an attacker to bypass the authentication mechanism and access the system.
Some of the ways the Vulnerable code can be mitigated is
For Inbound Authentication,
Implement a "first login" mode:
Instead of hard-coding default credentials, introduce a mechanism where users are required to enter a unique strong password or key during their initial login. This ensures that each user sets their own credentials. (as per CWE listed Potential Mitigations).Use secure storage for credentials:
Store the user's credentials in a secure manner, such as using cryptographic techniques to protect sensitive information. Avoid storing plaintext passwords or keys.Implement multi-factor authentication (MFA):
Consider implementing MFA, where users are required to provide additional verification factors (such as a one-time password or biometric data) along with their credentials. This adds an extra layer of security to the authentication process.
Mitigated Code
import java.util.Scanner;
public class MitigatedCode {
// Simulating a "first login" mode that requires the user to enter a unique strong password
private static boolean firstLogin = true; // A flag to indicate whether it is the first login or not
private static String username; // A variable to store the user's username
private static String password; // A variable to store the user's password
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
if (firstLogin) {
System.out.println("Welcome to the system. Please enter a unique username and a strong password.");
username = scanner.nextLine(); // Assume input validation and error handling
password = scanner.nextLine(); // Assume input validation and error handling
System.out.println("Thank you. Your credentials are saved.");
} else {
System.out.println("Please enter your username and password.");
username = scanner.nextLine(); // Assume input validation and error handling
password = scanner.nextLine(); // Assume input validation and error handling
}
authenticate(username, password);
// Clear credentials from memory
username = null;
password = null;
scanner.close();
}
public static void authenticate(String username, String password) {
// Perform authentication logic
// For demonstration purposes, compare with stored credentials
if (username.equals(username) && password.equals(password)) {
System.out.println("Authentication successful.");
if (firstLogin) {
System.out.println("Please change your password to a strong one.");
firstLogin = false; // Reset the flag after the first login
}
} else {
System.out.println("Authentication failed.");
}
}
}
The Mitigated code does the following:
The code demonstrates mitigation for CWE-798 by implementing a
first login
mode that requires the user to enter a unique strong password, for inbound Authentication.
Python
Python
Vulnerable Code
import requests
# Hard-coded credentials
username = "admin"
password = "secret"
# Outbound communication to an external component
response = requests.get("https://example.com/api", auth=(username, password))
# Inbound authentication using passwords
def login(user, pwd):
# Check the input credentials against a hard-coded set of credentials
if user == username and pwd == password:
return True
else:
return False
The above code is Vulnerable due to:
Hard-coded credentials:
The username and password are directly embedded in the code, making them easily accessible to anyone who has access to the source code.
Outbound communication:
The code sends the username and password as part of the HTTP request to the external API using the requests.get()
function. This means that the credentials are transmitted over the network in plain text, which is highly insecure.
Inbound authentication:
The login()
function compares the input credentials directly with the hard-coded credentials.
The Vulnerable code can be mitigated by:
Store credentials in a
secure configuration file
or database with appropriateaccess control
.Apply
strong one-way hash functions
with random salts to passwords before storing them.Use
secure protocols
such as HTTPS for transmitting sensitive information over the network.Implement a
secure authentication mechanism
that compares the hashed input password with the stored hash, rather than comparing plain-text passwords directly.
Mitigated Code
import requests
import hashlib
# Load credentials from a secure configuration file or database
with open("config.txt", "r") as f:
username, password_hash, salt = f.read().split()
# Outbound communication to an external component
response = requests.get("https://example.com/api", auth=(username, password_hash))
# Inbound authentication using passwords
def login(user, pwd):
# Apply strong one-way hash with salt to the incoming password
pwd_hash = hashlib.sha256((pwd + salt).encode()).hexdigest()
# Compare the hashed password with the stored hash
if user == username and pwd_hash == password_hash:
return True
else:
return False
The Mitigated code does the following:
It applies a
strong one-way hash
with a salt to the incoming password during authentication.The secure loading of credentials from a
configuration file or database
. It reads the username, password hash, and salt from the "config.txt" file, assuming they are stored securely.
References
Use of hard-coded password | OWASP Foundation
A07 Identification and Authentication Failures - OWASP Top 10:2021
How to Prevent Hardcoded Passwords?
GO Code Review #1 : Hard-coded credentials are security-sensitive
Last updated
Was this helpful?