Logging is essential for debugging, incident response, and collecting forensic evidence. Nevertheless, logging sensitive data raises many concerns, including the privacy of the stakeholders, limitations imposed by the law on the collection of personal information, and the potential for data exposure by insiders. Sensitive information includes, but is not limited to, IP addresses, user names and passwords, email addresses, credit card numbers, and any personally identifiable information such as social security numbers. Many countries prohibit or restrict collection of personal data; others permit retention of personal data only when held in an anonymized form. For example, leaking unencrypted credit card numbers into a log file could be a violation of PCI DSS (Payment Card Industry Data Security Standard) regulations [PCI 2010]. Consequently, logs must not contain sensitive data, particularly when prohibited by law.

Unfortunately, violations of this rule are common. For example, prior to version 0.8.1, the LineControl Java client logged sensitive information, including the local user's password, as documented by CVE-2005-2990.

The java.util.logging class provides a basic logging framework for JDK versions 1.4 and higher. Other logging frameworks exist, but the basic principles apply regardless of the particular logging framework chosen.

Programs typically support varying levels of protection. Some information, such as access times, can be safely logged. Some information can be logged, but the log file must be restricted from everyone but particular administrators. Other information, such as credit card numbers, can be included in logs only in encrypted form. Information such as passwords should not be logged at all.

For the following code examples, the log lies outside the trust boundary of the information being recorded. Also, normal log messages should include additional parameters such as date, time, source event, and so forth. This information has been omitted from the following code examples for brevity.

Noncompliant Code Example

In this noncompliant code example, a server logs the IP address of the remote client in the event of a security exception. This data can be misused, for example, to build a profile of a user's browsing habits. Such logging may violate legal restrictions in many countries.

When the log cannot contain IP addresses, it should not contain any information about a SecurityException, because it might leak an IP address. When an exception contains sensitive information, the custom MyExceptionReporter class should extract or cleanse it before returning control to the next statement in the catch block (see ERR00-J. Do not suppress or ignore checked exceptions).

public void logRemoteIPAddress(String name) {
  Logger logger = Logger.getLogger("com.organization.Log");
  InetAddress machine = null;
  try {
    machine = InetAddress.getByName(name);
  } catch (UnknownHostException e) {
    Exception e = MyExceptionReporter.handle(e);
  } catch (SecurityException e) {
    Exception e = MyExceptionReporter.handle(e);
    logger.severe(name + "," + machine.getHostAddress() + "," +
                  e.toString());
  }
}

Compliant Solution

This compliant solution does not log security exceptions except for the logging implicitly performed by MyExceptionReporter:

  // ...
  catch (SecurityException e) {
    Exception e = MyExceptionReporter.handle(e);
  }

Noncompliant Code Example

Log messages with sensitive information should not be printed to the console display for security reasons (a possible example of sensitive information is passenger age). The java.util.logging.Logger class supports different logging levels that can be used for classifying such information: FINEST, FINER, FINE, CONFIG, INFO, WARNING, and SEVERE. By default, the INFO, WARNING, and SEVERE levels print the message to the console, which is accessible by end users and system administrators.

If we assume that the passenger age can appear in log files on the current system but not on the console display, this code example is noncompliant.

logger.info("Age: " + passengerAge);

Compliant Solution

This compliant solution logs the passenger age at the FINEST level to prevent this information from displaying on the console. As noted previously, we are assuming the age may appear in system log files but not on the console.

// Make sure that all handlers only print log messages rated INFO or higher
Handler handlers[] = logger.getHandlers();
for (int i = 0; i < handlers.length; i++) {
  handlers[i].setLevel(Level.INFO);
}
// ...
logger.finest("Age: " + passengerAge);

Risk Assessment

Logging sensitive information can violate system security policies and can violate user privacy when the logging level is incorrect or when the log files are insecure.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

FIO13-J

Medium

Probable

High

P4

L3

Automated Detection

ToolVersionCheckerDescription
Parasoft Jtest
2023.1
CERT.FIO13.SENS
CERT.FIO13.LHII
CERT.FIO13.PEO
CERT.FIO13.CONSEN
Prevent exposure of sensitive data
Avoid logging sensitive Hibernate-related information at the 'info' level in 'log4j.properties' files
Do not pass exception messages into output in order to prevent the application from leaking sensitive information
Do not log confidential or sensitive information

Related Guidelines

MITRE CWE

CWE-359, Privacy Violation
CWE-532, Information Exposure through Log Files
CWE-533, Information Exposure through Server Log Files
CWE-542, Information Exposure through Cleanup Log Files

Android Implementation Details

DRD04-J. Do not log sensitive information is an Android-specific instance of this rule.

Bibliography



3 Comments

  1. The CS with the following advice sounds very dangerous:

    This compliant solution does not log security exceptions.

    • It should be made clear that security exceptions should be visible to admins but not to anyone across a trust boundary
    • Security exceptions can (and should) be logged but it is important to cleanse sensitive information such as SSNs before logging.
    • Logging IP addresses is fine as long as they are in the same trust domain.

    I think I also disagree with the last CS. It is better to simply not include passenger age in the log statement rather than specify log levels.

    1. This compliant solution does not log security exceptions.

      • It should be made clear that security exceptions should be visible to admins but not to anyone across a trust boundary
      • Security exceptions can (and should) be logged but it is important to cleanse sensitive information such as SSNs before logging.
      • Logging IP addresses is fine as long as they are in the same trust domain.

      Agreed. Personally, I think all logging should be done by the exception reporter, which saves you from having to decide logging on an individual basis. Amended the 1st NCCE/CS pair to dictate that MyExceptionReporter does some logging of its own, thus saving us from having to do it explicitly or show us doing none.

      I think I also disagree with the last CS. It is better to simply not include passenger age in the log statement rather than specify log levels.

      This was a priori considered OK in the corresponding NCCE. I've added text to make this clearer. AFAIK passenger ages is not illegal to log anywhere.

      1. This CS is a misuse of logging level.  Setting the level to FINEST is going to fill (console) logs with all sorts of other noise.  Obviously you can tune log level per class, but that is also quite error prone and doesn't help if the Devs have already done the 'right thing' in the classes that are logging sensitive information, and have stuff logged at DEBUG level (maps to FINE).

        And worse, if the (file) logger is ever set to FINEST you've now leaked that sensitive information.