CodeQL queries 1.24

Skip to end of metadata
Go to start of metadata

Name: Cleartext storage of sensitive information using 'Properties' class

Description: Storing sensitive information in cleartext can expose it to an attacker.

ID: java/cleartext-storage-in-properties

Kind: problem

Severity: warning

Precision: medium

Query: CleartextStorageProperties.ql
/**
 * @name Cleartext storage of sensitive information using 'Properties' class
 * @description Storing sensitive information in cleartext can expose it to an attacker.
 * @kind problem
 * @problem.severity warning
 * @precision medium
 * @id java/cleartext-storage-in-properties
 * @tags security
 *       external/cwe/cwe-313
 */

import java
import SensitiveStorage

from SensitiveSource data, Properties s, Expr input, Expr store
where
  input = s.getAnInput() and
  store = s.getAStore() and
  data.flowsToCached(input) and
  // Exclude results in test code.
  not testMethod(store.getEnclosingCallable()) and
  not testMethod(data.getEnclosingCallable())
select store, "'Properties' class $@ containing $@ is stored here. Data was added $@.", s,
  s.toString(), data, "sensitive data", input, "here"

Sensitive information that is stored unencrypted is accessible to an attacker who gains access to the storage.

Recommendation

Ensure that sensitive information is always encrypted before being stored. It may be wise to encrypt information before it is put into a heap data structure (such as Java.util.Properties) that may be written to disk later. Objects that are serializable or marshallable should also always contain encrypted information unless you are certain that they are not ever going to be serialized.

In general, decrypt sensitive information only at the point where it is necessary for it to be used in cleartext.

Example

The following example shows two ways of storing user credentials in a cookie. In the 'BAD' case, the credentials are simply stored in cleartext. In the 'GOOD' case, the credentials are hashed before storing them.

public static void main(String[] args) {
	{
		String data;
		PasswordAuthentication credentials =
				new PasswordAuthentication("user", "BP@ssw0rd".toCharArray());
		data = credentials.getUserName() + ":" + new String(credentials.getPassword());
	
		// BAD: store data in a cookie in cleartext form
		response.addCookie(new Cookie("auth", data));
	}
	
	{
		String data;
		PasswordAuthentication credentials =
				new PasswordAuthentication("user", "GP@ssw0rd".toCharArray());
		String salt = "ThisIsMySalt";
		MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
		messageDigest.reset();
		String credentialsToHash =
				credentials.getUserName() + ":" + credentials.getPassword();
		byte[] hashedCredsAsBytes =
				messageDigest.digest((salt+credentialsToHash).getBytes("UTF-8"));
		data = bytesToString(hashedCredsAsBytes);
		
		// GOOD: store data in a cookie in encrypted form
		response.addCookie(new Cookie("auth", data));
	}
}

References
  • The CERT Oracle Secure Coding Standard for Java: SER03-J. Do not serialize unencrypted, sensitive data.
  • M. Dowd, J. McDonald and J. Schuhm, The Art of Software Security Assessment, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.
  • M. Howard and D. LeBlanc, Writing Secure Code, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.
  • Common Weakness Enumeration: CWE-313.