John Melton's Weblog
Java, Security and Technology

Preventing Log Forging in Java

Print this article

No Gravatar

This article will provide a quick overview of log forging and discuss a couple simple solutions to prevent it.

First, what is log forging?

Logging is one of the most common things that an application does. Logging is a very generic term that can mean lots of different things, from debug style logging for the developer, up to and including functioning as the system audit log. The 3 most common logging mechanisms I see in real world use are:
1. System output (System.out.println)
2. 3rd party logging library (log4j, commons logging, slf4j, etc.)
3. DB Logging

System output
System output is a functional mechanism, but tends to provide spotty information at times, since developers often don’t log everything they should in order for the log to be functional. A simple example of this is that essentially all logging should include a timestamp and at least the logged in user if applicable, but System.out logging often doesn’t include these 2 basic pieces of information.

3rd party logging library
The 3rd party logging libraries are the workhorses of the java logging world. They are probably the most used option and for good reason. The popular frameworks provide very simple configuration, offer all the basic features (and even some advanced features), and can be setup to log the same “meta-information” for each log entry (such as timestamp, username, etc.).

DB Logging
Most often DB logging is used for log/audit data that needs to be maintained for a reasonable amount of time. If there is auditing going on for the application, a DB is a popular choice since the audit records can actually reference the data it is about using the relational DB mechanisms already built into the DB product. Also when logging to a DB, there is usually a reasonable amount of data that is stored. This is likely due to the fact that someone sat down and thought out what data should be stored, and created the DB schema to store that info – that way the standard for what data needs to be logged is perfectly clear to the developer.

Now that we’ve talked about a few basic types of logging, let’s see what log forging is. Let’s consider this bit of code.


String previousPage = request.getParameter("prev");
logger.info("Previous page from request was: " + previousPage);

This simple bit of code just writes a request parameter to the log. Pretty simple. Let’s consider two scenarios here. If the user is using the application as intended, something like the following might be sent in – “prev=viewCart”, telling the app the page the user was coming from was a view shopping cart page. This would result in the following being written in the log.


[2010-10-21 18:45:15] [bill] Previous page from request was: viewCart

Now what would happen if an attacker instead decided to modify the request parameter and instead entered “prev=viewCart\r\n[2010-10-21 18:45:15] [steve] Account successfully created” as the request parameter? (Note the data I entered above is not actually URL encoded for clarity, but would be in a real example) Now the log will look like the following:


[2010-10-21 18:45:15] [bill] Previous page from request was: viewCart
[2010-10-21 18:45:15] [steve] Account successfully created

Now the attacker has been able to create a forged entry in the application log which reduces the value of the logs, and frustrates any forensic type activities. This is the essence of log forging.

So how do I prevent it?

There are various options to prevent log forging. I’ll discuss just a few and my opinions of them.

1. Validate all input that could be put in the log file. This would involve doing strict whitelist validation to make sure that characters that pose issues in logs are not available to the attacker. This option, in my opinion, would be the least likely to work. The truth is that you’d have to validate lots of data, and if it failed validation, it wouldn’t get logged. That data could be valuable debugging information or even audit data. This is my least favorite option, and I’ve only actually seen it once in practice.

2. Log to a database. Essentially logging to a database does prevent log forging since carriage return / newline mean nothing in that context, but it introduces another possible exploit: SQL Injection. For information about how to prevent SQL Injection properly, please see: The OWASP Top Ten and ESAPI – Part 2 – Injection Flaws. This is an ok option if you need to use a database for auditing, but I wouldn’t use it for standard logging. If you do use it, be sure to use a proper SQL Injection prevention mechanism.

3. Encode all output. This is a simple and elegant solution, and my personal favorite. There’s not that much to it – just encode those characters you need to in order to prevent log forging, and everything else get’s logged the same. You can develop a simple wrapper around your favorite logging utility in order to do the log forging prevention work, and use the logging utility for all it’s other features. Luckily the good people who built ESAPI already did this for you. They have a logging component built into ESAPI that contains this log forging protection. An example for wrapping the popular Log4j library is here. Here is a snippet of code that shows their encoding in action.


// ensure no CRLF injection into logs for forging records
String clean = message.replace( '\n', '_' ).replace( '\r', '_' );
if ( ESAPI.securityConfiguration().getLogEncodingRequired() ) {
    clean = ESAPI.encoder().encodeForHTML(message);
    if (!message.equals(clean)) {
        clean += " (Encoded)";
    }
}

As you can see, the class simply replaces all carriage returns and line feeds with underscores, then, if configuration dictates, HTML encodes the message. If the original message to be logged is different from the encoded version, a simple ” (Encoded)” string is tacked onto the end of the log entry to denote that it required encoding of some type.

Other notes

Another possibility when writing data to a log that may or may not be true in your environment is XSS. Though it doesn’t sound clear at first, consider this possibility. You log all of your data to a flat file, then your team, an auditor, system admin, or anyone comes along and opens your log file in a fancy web based log viewer. If XSS attacks are stored in the log, then the log viewer would then be susceptible to XSS. The best solution, in my opinion, would be to ensure your log viewer is protected from XSS. I feel that when you output data to a particular location, you should protect against the attacks specific to that location, ie log output should protect against log forging. However, it is helpful to be aware of issues like this to understand the full situation. Also note in the ESAPI code above, HTML output encoding is performed, and could help prevent this situation as well.

Wrap-up

So, as you can see, log forging is an issue that affects pretty much every J2EE application out there. It’s fairly simple to understand and fairly simple to solve. Hope this helps. Let me know if you found it useful, or if you have dealt with log forging differently.

Be Sociable, Share!

Technorati Tags: , , , , , ,

Comments

6 Responses to “Preventing Log Forging in Java”

  1. Tweets that mention Preventing Log Forging in Java : John Melton's Weblog -- Topsy.com on September 23rd, 2010 8:47 PM

    [...] This post was mentioned on Twitter by d3v1l, Mike Haller, Marcin Zając, mingyen, Open Foundstone and others. Open Foundstone said: Preventing Log Forging in Java: This article will provide a quick overview of log forging and discuss a couple sim… http://bit.ly/b1DZIA [...]

  2. JeremyNo Gravatar on October 21st, 2010 8:33 PM

    So by doing this, how would one differentiate in a logged message the difference between an _ and CR/LF? because you’ve replaced them, you can’t. Not that this is likely a huge issue – but I’m more a fan of HTML Encoding the data, including the CR/LF. That way you can get the original logged data back if needed for some reason. Only downside might be the expense of added work when logging…

  3. johnNo Gravatar on October 21st, 2010 11:09 PM

    @Jeremy
    Good point. If you want absolute certainty that you got exactly what was being logged, you could HTML encode the entire message. However, in practice, as you mentioned, I’m not sure I would personally worry over that issue very much. Either way, you’ll know that CR/LF is not going to be able to cause forged entries in your log.

  4. EricNo Gravatar on March 9th, 2011 10:39 AM

    Sorry for dredging up a post from October…but I wanted to comment on another log forging case. What about a size limit on the amount of input data? Blocking CR/LF is good, but I think that being able to fill the log files with useless characters could also be an attack vector. Not very stealthy, but could be useful.

  5. johnNo Gravatar on March 9th, 2011 10:51 AM

    @Eric,
    Yep, this is a good point. I generally see this more related to restricting the size of your input. If you have length restrictions on incoming data that you are logging (request parms, headers, data from DB, etc.), then you are probably ok. However, you could certainly take the route of limiting the length of every log entry. The issue there is that an attacker could fill to your limit with a few fields, and the remainder (where the actual attack might be) might not get logged. I think individual restrictions on field length is probably a safer route to go, given that logs can be used forensically, so you probably don’t want to lose some of that important data. Nice catch though.

  6. Year Of Security for Java – Week 12 – Log Forging Prevention : John Melton's Weblog on March 20th, 2012 10:54 PM

    [...] actually already written a longer, more detailed article about log forging prevention here, but this shorter version was meant to show the essentials and fits in with the year of security [...]

Leave a Reply