Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Parasoft Jtest 2022.2

Any time an application stores a password Programs that store passwords as cleartext (unencrypted text data) , its value is potentially exposed risk exposure of those passwords in a variety of ways. To prevent this information from being inadvertently leaked, this exposure must be limited. While a program will receive the password from the user Although programs generally receive passwords from users as cleartext, this they should be the last time it is in this form.ensure that the passwords are not stored as cleartext.

An acceptable technique for limiting the exposure of passwords is the use of hash functions, which Hash functions allow programs to indirectly compare an input password to the original , password string without storing a cleartext or decryptable version of the password. This approach minimizes the exposure of the password without presenting any practical disadvantages.

Cryptographic Hash Functions

The value that produced by a hash function outputs is called the hash value. Another term for hash value is or message digest. Hash functions are computationally feasible functions whose inverses are computationally infeasible. This means that in In practice, one can encode a password can be encoded to a hash value, while they are also unable to decode itbut decoding remains infeasible. The equality of the passwords can be tested through the equality of their hash values.

It is important that you append A good practice is to always use a salt in addition to the password you are hashingbeing hashed. A salt is a unique randomly generated piece of data that is stored along with and used to generate the hash value . The use of a salt helps prevents brute-force attacks against the hash value, provided the salt is long enough. Each along with the password. Each password should have its own salt associated with it. If  If a single salt were used for more than one password an attacker could determine when a user has a commonly used password, two users would be able to see if their passwords are the same. Password specific salts are usually stored along with their corresponding hash values. In addition to password-unique salts, system-unique salts that are stored separately from the hash values may also be used to increase the difficulty of deriving passwords if a malicious actor obtains a copy of the hash values and salts.

The choice of hash function and salt length presents a trade-off between security and performance. If it takes longer to compute a hash value, then the performance of a brute-force attack will be lowered. This will come at the cost of slowing down the program when it validates passwords. If a longer salt length is used, then the performance of a brute-force attack will be lowered at the cost of the extra storage space required.Increasing the effort required for effective brute-force attacks by choosing a stronger hash function can also increase the time required to validate a password.  As time passes best practices around password management evolve to keep password derivation computationally infeasible.  The documents NIST 800-63 and OWASP ASVS are good places to consult for the current best practices around cryptographic hashing.

Java's javax.crypto package provides implementations of various cryptographic hash functions. Avoid functions that have known weaknesses, such as the Message-Digest Algorithm (MD5). Java's MessageDigest class provides the functionality of various cryptographic hash functions. Be careful not to pick a defective function such as MD-5. Publications are often available when a hash function is proven defective. Hash functions such as SHA-1 and SHA-2 are maintained by the NSA, and are currently considered safe.

Noncompliant Code Example

This noncompliant code example encrypts and decrypts the password stored in credentials.pw. password.bin using a symmetric key algorithm:

Code Block
bgColor#FFcccc

public final class Password {
  private void setPassword(byte[] pass) throws Exception {
      // Arbitrary encryption scheme
    bytesbyte[] encrypted = encrypt(pass); //arbitrary encryption scheme
    clearArray(pass);    
    // Encrypted    password to password.bin
    saveBytes(encrypted,"password.bin");
  //encrypted password to password.binclearArray(encrypted); 
  }

  private boolean checkPassword(byte[] pass) throws Exception {
    // Load the boolean arrays_equal;encrypted password
    byte[] encrypted = loadBytes("password.bin"); //load the encrypted password
    byte[] decrypted = decrypt(encrypted);
    arrays_equalclearArray(encrypted);
    boolean arraysEqual = Arrays.equal(decrypted, pass);
    clearArray(decrypted);
    clearArray(pass);
    return arrays_equalarraysEqual;
  }

  private void clearArray(byte[] a) {
    for (int i = 0; i < a.length; i++) {
      a[i] = 0;
    }
  }

  private byte[] encrypt(byte[] clearValue) {
    //set all of the elements in a to zero ... symmetric encryption of clearValue bytes, returning the encrypted value
  }

  private byte[] decrypt(byte[] encryptedValue) {
    // ... symmetric decryption of  encryptedValue bytes, returning clear value
  }

  private void saveBytes(byte[] bytes, String filename) throws IOException {
    // ... write bytes to the file
  }
  
  private byte[] loadBytes(String filename) throws IOException { 
    // ... read bytes to the file 
  }
}

This is a very simple password mechanism that only stores one password for the system.  The flaw in this approach is that the stored password is encrypted in a way that it can be decrypted to compare it to the user's password input. An attacker could potentially decrypt this the password file to discover the password. This attacker could be someone knows or has figured out the encryption scheme being used by the program, particularly when the attacker has knowledge of the key and encryption scheme used by the program. Passwords should be protected even from system administrators and privileged users. Consequently, using encryption is only partly effective in mitigating password disclosure threats.

Noncompliant Code Example

This noncompliant code examples implements example uses the SHA-1256 hash function through the MessageDigest class to compare hash values instead of cleartext strings. It uses SecureRandom to generate a strong salt, as recommended by MSC02-J. Generate strong random numbers.  However, it uses a String to store the password:

Code Block
bgColor#FFcccc

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public final class Password {
  private SecureRandom random = new SecureRandom();

  private void setPassword(String pass) throws Exception {
    byte[] salt = generateSalt(12new byte[12];
    random.nextBytes(salt);
    MessageDigest sha_1msgDigest = MessageDigest.getInstance("SHA-1256");
    // Encode the string and salt
    byte[] hashVal = sha_1msgDigest.digest((pass+salt).getBytes()); //encode the string and salt
    saveBytes(salt, "salt.bin");
    saveBytes(hashVal,"password.bin"); //save Save the hash value to credentials.bin password.bin
    saveBytes(hashVal,"password.bin");
  }

  private boolean checkPassword(String pass) throws Exception {
    byte[] salt = loadBytes("salt.bin");
    MessageDigest sha_1msgDigest = MessageDigest.getInstance("SHA-1256");
    // Encode the string and salt
    byte[] hashVal1 = sha_1msgDigest.digest((pass+salt).getBytes());
    //encode Load the hash stringvalue stored andin saltpassword.bin
    byte[] hashVal2 = loadBytes("password.bin"); //load the hash value stored in password.bin
    return Arrays.equals(hashVal1, hashVal2);
  }

  private void saveBytes(byte[] generateSalt(int n) { bytes, String filename) throws IOException {
    // ... write bytes to the file
  }   

  private byte[] loadBytes(String filename) throws IOException { 
    //Generate a... randomread bytebytes arrayto ofthe lengthfile n
  }
}

Even if This is a very simple password mechanism that only stores one password and one salt for the system. Even when an attacker knows that the program stores passwords using SHA-1256 and a 12-byte salt, they he or she will be unable to get retrieve the value of the actual password from password.bin and salt.bin.

While Although this fixes approach solves the decryption problem from the previous noncompliant code example, at runtime this code program may inadvertently store the passwords as cleartext . This is because the pass arguments may not be cleared from memory by the Java garbage collector. See MSC10in memory. Java String objects are immutable and can be copied and internally stored by the Java Virtual Machine. Consequently, Java lacks a mechanism to securely erase a password once it has been stored in a String. See MSC59-J. Limit the lifetime of sensitive data for more information.

Compliant Solution

This compliant solution addresses the problems from the previous noncompliant code examples.:

Code Block
bgColor#ccccff
import java.security.GeneralSecurityException;
import java.security.MessageDigestSecureRandom;
import java.security.NoSuchAlgorithmException;

public .spec.KeySpec;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
  
final class Password {

  private void setPassword(byte[] pass) throws Exception {SecureRandom random = new SecureRandom();
  private final byte[] saltint SALT_BYTE_LENGTH = generateSalt(12);
  private final byte[]int inputITERATIONS = appendArrays(pass, salt)100000;
  private final MessageDigestString sha_1ALGORITHM = MessageDigest.getInstance("SHA-1");
    byte[] hashVal = sha_1.digest(input); //encode the string and salt    
    clearArray(pass);    
    clearArray(input"PBKDF2WithHmacSHA256";
    
  /* Set password to new value, zeroing out password */
  void setPassword(char[] pass)
      throws IOException, GeneralSecurityException  {
    byte[] salt = new byte[SALT_BYTE_LENGTH];
    random.nextBytes(salt);
    saveBytes(salt, "salt.bin");    
     byte[] hashVal = hashPassword(pass, salt); 
    saveBytes(hashVal,"password.bin");
 //save the hash value to credentials.pw Arrays.fill(hashVal, (byte) 0);
  }

  private /* Indicates if given password is correct */
  boolean checkPassword(bytechar[] pass)
      throws ExceptionIOException, GeneralSecurityException  {
    byte[] salt = loadBytes("salt.bin");
    byte[] inputhashVal1 = appendArrayshashPassword(pass, salt);
    // Load the hash value stored in password.bin
    MessageDigest sha_1byte[] hashVal2 = MessageDigest.getInstanceloadBytes("SHA-1password.bin");
    boolean arraysEqual = byte[] hashVal1 = sha_1.digest(input); //encode the string and salt
    clearArray(passtimingEquals(hashVal1, hashVal2);
    Arrays.fill(hashVal1, (byte) 0);
    Arrays.fill(hashVal2, (byte) 0);
    return arraysEqual;
  }
  
  /* Encrypts password & salt and zeroes both */
  private byte[] hashPassword(char[] pass, byte[] salt)
      throws GeneralSecurityException {
    KeySpec spec = new PBEKeySpec(pass, salt, ITERATIONS);
    Arrays.fill(pass, clearArray(inputchar) 0);
    byte[] hashVal2 = loadBytes("credentials.pw"); //load the hash value stored in credentials.pw
    return Arrays.equals(hashVal1, hashVal2);
  }

  private byte[] generateSalt(int n) {
    //Generate a random byte array of length n
  }

  private byte[] appendArrays(byte[] a, byte[] b) Arrays.fill(salt, (byte) 0);
    SecretKeyFactory f = SecretKeyFactory.getInstance(ALGORITHM);
    return f.generateSecret(spec).getEncoded();
  }

  /**
   * Indicates if both byte arrays are equal
   * but uses same amount of time if they are the same or different
   * to prevent timing attacks
   */
  public static boolean timingEquals(byte b1[], byte b2[]) {
    boolean result = true;
    int len = b1.length;
    if (len != b2.length) {
      result = false;
    }
    if (len > b2.length) {
      len = b2.length;
    }
    for (int i = 0; i < len; i++) {
      result &= (b1[i] == b2[i]);
    }
    return result;
  }

  private void saveBytes(byte[] bytes, String filename) throws IOException {
    //Return a... newwrite arraybytes ofto a appended to bthe file
  }

  private void clearArray(byte[] loadBytes(String afilename) throws IOException {
    //set all... ofread thebytes elementsto in a to zerothe file
  }
}

This is a very simple password mechanism that only stores one password and one salt for the system.

First, this compliant solution uses byte array to store the password.

In both the setPassword() and checkPassword() methods, the cleartext representation of the password is erased as soon as immediately after it is converted into a hash value. After this happens, there is no way for an attacker to get the password as cleartext. 

Exceptions

Consequently, attackers must work harder to retrieve the cleartext password after the erasure. Providing guaranteed erasure is extremely challenging, is likely to be platform specific, and may even be impossible because of copying garbage collectors, dynamic paging, and other platform features that operate below the level of the Java language.

Furthermore, we use a timingEquals() method to validate the password. While doing a simple byte comparison, it takes the same time for both successful matches and unsuccessful ones; consequently thwarting timing attacks.

Finally, it uses PBKDF2 which, unlike MessageDigest, is specifically designed for hashing passwords.

The parametric values (SALT_BYTE_LENGTH, ITERATIONS, ALGORITHM) should be set to values that reflect current best practices.  It should also be noted that once these parametric values are set they can not be changed without having to re-hash all passwords with the new parametric values.  

Applicability

Passwords stored without a secure hash are exposed to malicious users. Violations of this guideline generally have a clear exploit associated with them.

Applications MSC18-EX0 Applications such as password managers may need to retrieve the original password in order to enter it into a third-party application. This is okay permitted even though it violates the this guideline. The difference here is that the password manager is accessed by a single user . The program will always have and always has the user's permission to store their passwords in this way. Therefore, provided the user is competent, his or her passwords and to display those passwords on command. Consequently, the limiting factor to safety and security is the user's competence rather than the program's operation will be safe. 

Risk Assessment

Violations of this rule have to be manually detected because it is a consequence of the overall design of the password storing mechanism. It is pretty unlikely, since it will occur around once or twice in a program that uses passwords. As demonstrated above, almost all violations of this rule have a clear exploit associated with them.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

MSC18-J

medium

likely

high

P6

L2

Bibliography

Wiki Markup
\[[API 2006|AA. Bibliography#API 06]\] Class {{java.security.MessageDigest}}

http://www.javapractices.com/topic/TopicAction.do?Id=216 Passwords never in clear text

http://en.wikipedia.org/wiki/Salt_(cryptography) Salt (cryptography)

http://en.wikipedia.org/wiki/Cryptographic_hash_function Cryptographic hash function

.

Automated Detection

ToolVersionCheckerDescription
Parasoft Jtest
Include Page
Parasoft_V
Parasoft_V
CERT.MSC62.PCCF
CERT.MSC62.PWDPROP
CERT.MSC62.PWDXML
CERT.MSC62.WCPWD
CERT.MSC62.WPWD
CERT.MSC62.PLAIN
CERT.MSC62.PTPT
CERT.MSC62.UTAX
Avoid storing usernames and passwords in plain text in Castor 'jdo-conf.xml' files
Ensure that passwords are not stored as plaintext and are sufficiently long
Ensure that passwords are not stored as plaintext and are sufficiently long
Avoid unencrypted passwords in WebSphere 'ibm-webservicesclient-ext.xmi' files
Avoid unencrypted passwords in WebSphere 'ibm-webservices-ext.xmi' files
Password information should not be included in properties file in plaintext
Avoid using plain text passwords in Axis 'wsdd' files
Avoid using plain text passwords in Axis2 configuration files

Bibliography


...

Image Added Image Added Image Addedhttp://nsa.gov/&nbspImage Removed;