Hardcoded Cryptographic Salt
ID |
java.hardcoded_cryptographic_salt |
Severity |
high |
Resource |
Predictability |
Language |
Java |
Tags |
CWE:760, NIST.SP.800-53, OWASP:2021:A2, PCI-DSS:6.5.3 |
Description
"Salting" is a technique used in some cryptographic operations:
-
With password hashing, a salt is typically used to prevent dictionary or 'rainbow' table attacks using massive pre-computed tables of hashed common passwords.
-
With key derivation functions (KDF), such as PBKDF2, scrypt or Argon2, a salt is used to prevent the same key being derived from the same input password.
-
With digital signatures and message authentication schemes, salts often add randomness to the message being signed or authenticated, making it harder for attackers to forge signatures or extract private keys through cryptoanalysis.
The use of a hardcoded cryptographic salt in applications can severely compromise the security of cryptographic processes. In password hashing, for example, a salt is typically used to ensure that even if two users have the same password, their hashed outputs will differ.
However, if the salt is hardcoded into the application’s source code, it becomes predictable and defeats the purpose of introducing randomness, making the application susceptible to attacks such as dictionary and rainbow table attacks.
Rationale
Hardcoding cryptographic salts within the source code is a common error that can reduce the effectiveness of hash functions used to secure sensitive information, like passwords.
A salt should be unique and random for each cryptographic operation to ensure that the results are distinct, even for identical inputs. By hardcoding a salt, attackers can reverse-engineer the application to discover the salt, allowing them to perform attacks that target the hashed data.
Consider the following Java example where the cryptographic salt is hardcoded:
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class CryptographyExample {
private static final String SALT = "HardCodedSalt123";
public static String hashPassword(String password) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(SALT.getBytes()); // Using the hardcoded salt
md.update(password.getBytes());
byte[] byteData = md.digest();
StringBuilder sb = new StringBuilder();
for (byte b : byteData) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
}
In this example, the constant SALT
is hardcoded and used during the hashing process, increasing vulnerability to pre-compiled attack vectors.
Remediation
To remediate the issue of a hardcoded cryptographic salt, developers should generate a unique, random salt for each cryptographic operation. This ensures the robustness of the hash function by making the output unique even for identical inputs.
Generate a unique, non-predictable salt for each cryptographic operation. Store the generated salt in clear text along with the hashed/encrypted data to allow so the salt could be retrieved during the verification process. And never reuse a salt !
In the 1970s 12 bits of salt were common and appropriate for the computational and storage capacity at that time. Today, at least 128 bits of salt are recommended and generally are robust enough for most use cases. |
Here is a revised version of the previous example incorporating best practices for securely generating a salt:
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
public class SecureCryptographyExample {
public static String hashPassword(String password) {
byte[] salt = generateSalt(); // Generate a new random salt
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(salt); // Use the dynamically generated salt
md.update(password.getBytes());
byte[] byteData = md.digest();
StringBuilder sb = new StringBuilder();
for (byte b : byteData) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
private static byte[] generateSalt() {
SecureRandom sr = new SecureRandom();
byte[] salt = new byte[16];
sr.nextBytes(salt); // Potentially larger size for stronger security
return salt;
}
}
In this improved version, the generateSalt
method utilizes the SecureRandom
class to produce a cryptographically strong random salt. This approach greatly enhances security by ensuring that salts are unique and unpredictable for each hashing operation. The generated salts should be stored alongside the hash in a secure manner to allow for proper validation and verification during future authentication checks.