What is it and why do I care?
Clickjacking is a type of “web framing” or “UI redressing” attack. What that simply means in practice is that:
1. A user (victim) is shown an innocuous, but enticing web page (think watch online video)
2. Another web page (that generally does something important – think add friends on social network) is layered on top of the first page and set to be transparent
3. When the user thinks they are clicking on the web page they see (video), they are actually clicking on the higher layered (framed) page that is transparent
This attack is clever, and there are some interesting specifics in the actual execution of an attack (For more info, see the references), but here, I’m concerned with preventing the attack.
What should I do about it?
There is still no perfect answer on clickjacking, but things are getting better, especially as users upgrade to more modern browsers. The recommendation is two-fold:
1. Use the X-Frame-Options HTTP header
2. Include framebusting code
There is a future article in the series coming, I promise, on the X-Frame-Options HTTP header. All I’ll say for now is that this header is the more robust solution, but that it requires a relatively modern browser. Fortunately, folks are slowly moving towards more modern browsers, so the situation is improving.
As for the framebusting recommendation, it is breakable, but should still be done. It certainly raises the bar. There are many options for framebusting code, but the folks at Stanford put together a paper http://seclab.stanford.edu/websec/framebusting/ on framebusting where they evaluated the current code in the wild and showed ways to break it. They came up with their own proposed solution in the paper. I’ll omit the code here, but it’s at the top of page 11 of the pdf. The basic idea is to both:
a) use the stylesheet to disable display for the entire body of the page, and
b) use Javascript to either enable the display if not framed, or to bust out of the frame if framed.
This solution will probably (if it’s not already) be broken, but it appears to be the best we have today.
Clickjacking is unfortunately a less-than-clearcut issue to solve, but by combining a couple different approaches, you can resolve the issue with a fair amount of robustness.
Update 2/3/2012: The Stanford approach does not adequately support IE in all instances – here’s a post from August Detlefsen explaining the solution. (h/t Chris Schmidt)
References
———–
https://www.owasp.org/index.php/Clickjacking
http://seclab.stanford.edu/websec/framebusting/
http://michael-coates.blogspot.com/2010/08/x-frame-option-support-in-firefox.html
https://www.codemagi.com/blog/post/194
What is it and why do I care?
Session cookies (or the cookie containing the JSESSIONID to Java folks) are the cookies used to perform session management for web applications. These cookies hold the reference to the session identifier for a given user, and the same identifier is maintained server-side along with any session scoped data related to that session id. Since cookies are transmitted on every request, this is the most common mechanism used for session management in web applications.
The HttpOnly flag is an additional flag that is used to prevent an XSS (Cross-Site Scripting) exploit from gaining access to the session cookie. Since gaining access to the session cookie, and subsequently hijacking the victim’s session, is one of the most common results of an XSS attack, the HttpOnly flag is a useful prevention mechanism.
What should I do about it?
The resolution here is quite simple. You must add the HttpOnly flag to your session cookie (and preferably all cookies).
Here’s an example of how a session cookie might look without the HttpOnly flag:
Cookie: jsessionid=AS348AF929FK219CKA9FK3B79870H;
And now, with the HttpOnly flag:
Cookie: jsessionid=AS348AF929FK219CKA9FK3B79870H; HttpOnly;
And, if you were following along from last week, with both the secure and HttpOnly flags:
Cookie: jsessionid=AS348AF929FK219CKA9FK3B79870H; HttpOnly; secure;
Not much to it. You can obviously manually do this, but if you’re working in a Servlet 3.0 or newer environment, there’s a simple configuration setting in the web.xml that takes care of this for you. You should add this snippet to your web.xml.
true
And, if you also use the secure flag, it looks like this:
true true
As you can see, resolving this issue is quite simple. It should be on everyone’s TODO list.
References
———–
http://blog.mozilla.com/webappsec/2011/03/31/enabling-browser-security-in-web-applications/
http://michael-coates.blogspot.com/2011/03/enabling-browser-security-in-web.html
https://www.owasp.org/index.php/HttpOnly
This is usually a Java-only site, but I thought this paper was fairly interesting, so thought I’d do a quick post. The implementation is .NET, but the concepts are transferrable.
The good folks at Microsoft Research have come up with a clever new technique for XSS “prevention” called ScriptGard. The paper is located here. (Looks like there was a previous version of the paper in 2010, but this is the latest updated copy.) The paper is a good read, but I just wanted to summarize for folks with short attention spans like me :>.
Essentially, they’ve come up with a performant solution for runtime context-sensitive XSS protection in legacy applications, without requiring changes to the code. That’s quite an achievement, so how do they do it?
Here are the basic steps:
[Training phase]
1. Instrument the code and insert hooks to perform taint propagation
2. Apply a simulation algorithm to execute the code and see where tainted data reaches a sink
3. Evaluate whether or not the trace (flow) from source to sink is XSS’able (via a browser implementation that actually analyzes the output context)
4. Mark and cache any “bad” flows
[Runtime phase]
5. If any “bad” flows are executed, process the input and appropriately encode/sanitize the output.
There is a lot more that you can get from the paper, but that’s the gist as I read it.
There are several interesting points to consider from the paper:
- The proposed solution is meant to work on legacy code, in contrast to templating libraries which seem to be a good solution for new code. Templating libraries are good in that they help structure the code better and provide a better separation of code and data, but that doesn’t really help for legacy code, which is quite a challenge. [templating libraries such as OWASP jxt or Google AutoEscape are examples from Java]
- They initially tried doing all this work at runtime, but it was prohibitive from a performance perspective (one extreme example noted 175X – not %, 175 times – worse performance). This meant the process had to be broken up and some data carried over from testing and analysis to runtime.
- They found a significant number of examples in real tested code where a) the wrong encoding was used [bad, common], b) encoding was applied, but not necessary [ok, reasonably common], or c) the right encoders were applied, but in the wrong order [bad, becoming more common]. Lesson: applying encoding/sanitization is hard, even if you are paying attention and know what you’re doing. The rules can become somewhat esoteric, especially when browser bugs cause weird things to happen in corner cases and browser vendors don’t always agree on how things should be handled. Automation is your friend here.
- In order to figure out the context, they actually had to include a browser. I’ve been saying this was required for years now, but had no idea how to make it performant. Looks like they are smarter than I am (DOH!). This does have a certain issue, however, regarding browser implementation quirks. What if the internal browser implementation is wrong? Now the trained algorithm is wrong and the sanitization is wrong …
In conclusion, this paper is a good read if you have the time. XSS doesn’t appear to be going away anytime soon, but research like this gives me hope for novel ways of solving the problem.
Thanks to @securityninja for pointing this paper out.
What is it and why do I care?
I’ve already discussed this particular entry in more detail as it’s part of the OWASP Top 10, so you can find more detail here – http://www.jtmelton.com/2010/06/02/the-owasp-top-ten-and-esapi-part-7-information-leakage-and-improper-error-handling/. In this article, I’ll just cover the important bits.
Error or exception handling is an important, often ignored, part of any application. There is a lot to be said about the topic in general, but for brevity’s sake, I’m only going to cover a couple of the most critical cases in J2EE web applications.
Essentially, one of the biggest worries about exception handling is that you don’t actually handle the exception. Instead your code or the code of some 3rd party library you’re using allows an exception to bubble up. At that point, once it’s at the boundary of your application and gets to the container, it depends on the specific container / application server you are using as to what semantics are applied in the handling of the exception. Often times, by default, there is a standard error page applied and the exception stack trace is simply printed on the screen in all it’s glory. This is clearly a problem in that it gives attackers a lot of information about the system, and can certainly lead to further attacks.
What should I do about it?
Handling this issue is fairly straightforward. The basic advice is to provide error handlers for at least java.lang.Throwable (catches any Java exceptions or errors) and provide more specific handlers for specific exceptions as well as http error codes, the most common being 404 and 500. An example snippet that can be applied to the web.xml is below:
Note: error.jsp page should be generic and provide a canned response message of some type with no detail that could help an attacker fingerprint the app in any way.
404 /error.jsp 500 /error.jsp java.lang.Throwable /error.jsp
There’s plenty more to handling exceptions in your application, but from a security perspective, catching Throwable’s and the specified error codes should do fairly well for you.
References
———–
http://software-security.sans.org/blog/2010/08/11/security-misconfigurations-java-webxml-files
http://www.jtmelton.com/2010/06/02/the-owasp-top-ten-and-esapi-part-7-information-leakage-and-improper-error-handling/
What is it and why do I care?
Session fixation, by most definitions, is a subclass of session hijacking. The most common basic flow is:
1. attacker gets a valid session ID from an application
2. attacker forces the victim to use that same session ID
3. attacker knows the session ID that the victim is using and can gain access to the victim’s account.
Step 2 of forcing the session ID on the victim is the only real work involved in the attack. It’s often performed by simply sending a victim a link to a website with the session ID attached to the URL.
Obviously, one user being able to take over another user’s account is a serious issue, so …
What should I do about it?
Fortunately, resolving session fixation is usually fairly simple. The basic advice is:
Invalidate the user session once a successful login has occurred.
The usual basic flow to handle session fixation prevention looks like:
1. User enters correct credentials
2. System successfully authenticates user
3. Any existing session information that needs to be retained is moved to temporary location
4. Session is invalidated (HttpSession#invalidate())
5. New session is created (new session ID)
6. Any temporary data is restored to new session
7. User goes to successful login landing page using new session ID
A useful snippet of code is available from the ESAPI project that shows how to change the session identifier.
http://code.google.com/p/owasp-esapi-java/source/browse/trunk/src/main/java/org/owasp/esapi/reference/DefaultHTTPUtilities.java (look at the changeSessionIdentifier method)
There are other activities that you can perform to provide additional assurance against this issue. A few I thought of are listed below.
1. Check if a user tries to login using a session ID that has been specifically invalidated (requires maintaining this list in some type of LRU cache)
2. Check if a user tries to use an existing session ID already in use from another IP address (requires maintaining this data in some type of map)
3. If you see these types of obviously malicious behavior, consider using something like AppSensor (shameless plug) to protect your app, and to be aware of the attack.
As you can see, session fixation is a serious issue, but has a pretty simple solution. Your best bet if possible is to include an appropriate solution in some “enterprise” framework (like ESAPI) so this solution applies evenly to all your applications.
References
———–
https://www.owasp.org/index.php/Session_fixation
http://www.acros.si/papers/session_fixation.pdf
http://cwe.mitre.org/data/definitions/384.html
http://projects.webappsec.org/w/page/13246960/Session%20Fixation
Year Of Security for Java
This will serve as the introduction for a new series that will have roughly 1 article per week for a year. This series will be different from my last series (OWASP Top Ten – Java) in that each article will be pretty short and focused. There are several motivations for this series:
1. Get some old topics written down
2. Research some new technologies
3. Write
4. Learn
5. Answer questions from Java friends
It’s the last one that serves as the primary motivation. In my work with Java developers, I understandably get asked a lot of questions about security. These are pretty far-ranging from the “what is this thing I heard about” to “how do I do this very specific thing correctly”. Developers are sharp, but have a lot they are held accountable for, of which security is only one. In this series, I hope to highlight some of the common issues the developers I work with ask me about frequently, as well as point out a few things they probably should be asking about, but don’t know to just yet.
If you have specific suggestions for articles you’d like to see, feel free to email me at domain_name at gmail dot com or on twitter (_jtmelton).
Hope you enjoy.
Please forgive the title, but today’s topic is something to be wary of if you write (or use) any access control / authorization type code in web-based j2ee apps: HTTP URL path parameters. Many people are unfamiliar with them (as they are uncommon), but they are something you should be aware of. A nice simple description of url path parameters can be found here. Essentially path parameters are the bit of a url path that comes after a semi-colon (semi-colon is the most popular path parameter delimeter). So, here’s an example of 2 urls, each with an http path parameter:
http://www.mysite.com/admin/UpdateUserServlet;jsessionid=OI24B9ASD7BSSD http://www.mysite.com/admin/UpdateUserServlet;/user/HomeServlet
We’ve all seen the first example probably many times where a jsessionid gets attached to our url. However, take a look at the second example. Pay very close attention to what is being presented here. This represents a request that is going to go to the administrative UpdateUserServlet, but with a path parameter of /user/HomeServlet. Now, what could be the problem here? Well, there actually turns out to be 2 different issues to deal with in most cases.
The first issue to contend with is how your servlet container/app server product and version handles certain request APIs, as apparently different products and even versions deal with http path parameters in different ways. (I have not done the work to determine which servers and versions are affected, but you should do that in your own environment, as apparently even configuration changes can cause slightly differing behavior. These variations are caused by – read blamed on – a lack of clarity in the servlet spec regarding path parameters.)
This problem can be seen when using certain API calls from the HttpServletRequest object and seeing how those APIs handle path parameters. Two of the affected methods are getContextPath() and getServletPath(), where there are variations between whether or not these calls actually strip out any path parameters depending on server and version. Again, this testing is left as an exercise to the reader. We’ll see below what can happen when we make poor assumptions here.
Here is where the actual problem really shows up … when we actually use these APIs. One of the most common uses is for writing access control / authorization code. Many access control frameworks or internal codebases use a url mapping concept of some kind. They vary widely in how they are implemented, but a simple example might be: anything with “/admin/” in the path requires the admin role, or anything that ends in “UpdateServlet” requires the manager role. Let’s use the “ends with” example and walk through some code.
String uri = request.getRequestURI(); //note getRequestURI will always return the full path with path parameters but not request parameters
if (uri.endsWith("UpdateServlet")) {
//require the manager role here
} else {
//just require standard user role
}
This is a very trivial piece of code, but will be similar in spirit to what is in lots of access control code in j2ee apps. Here the developer was expecting the user to send a request that looked like
http://www.mysite.com/app/UserUpdateServlet
when they were trying to get to the update servlet. But what happens if the user sends a request like
http://www.mysite.com/app/UserUpdateServlet;/app/UserReadServlet
HERE’S THE PROBLEM! Now the app code has checked the URI, and sees that it ends with ReadServlet and not UpdateServlet, so it only requires the standard user role, and the access control check passes. But the app server/container sees that the ACTUAL request is going to UserUpdateServlet, and allows the user to go there. Now we have a access control bypass issue! The user has been able to circumvent your “protection”.
DOH! Ok, now what …?
There are several ways you could address this issue, and each option varies in difficulty and correctness.
1. You could whitelist all of your allowed requests and compare them to pre-determined acceptable urls, but that might get cumbersome with a very large app.
2. You can perform some cleansing (stripping) of the url path parameters, but that can be an issue if your app server allows various path parameter delimeters.
3. You can also compare from the start of the URI or path instead of checking the end. This might be similar to the whitelist option
4. Another option that should definitely be used is to check your app server/container (on every upgrade as well) to see what it’s actual behavior is regarding path parameters).
5. Another option might be to perform your access control check at the beginning of a request handling piece of code, like a servlet, or action. That way, you know that’s the code actually being executed, so it’s the url you should be verifying. This has the problem of a lack of centralized control however.
There are certainly more options here, and you know what will work in your code, but hopefully the options above help as a starting point. Hopefully you found this information helpful and are able to update your projects to fix the issue if it exists.
Much of my research for this article came from an important bug in the Spring Security (formerly Acegi) project that was caused by this path parameter issue (bug found by Ed Schaller). More information can be found at the following 2 urls.
http://www.springsource.com/security/cve-2010-3700
http://seclists.org/fulldisclosure/2010/Oct/437
This topic was first shared with me by Abraham Kang. He both introduced me to this issue and reviewed this article for me. Thanks Abraham!
This article is a basic introduction to AppSensor, an OWASP project that’s been gaining a lot of traction recently. It’s a fairly simple concept, and one that I think (and hope) will be implemented in lots of applications in the near future. If you’d rather watch a video about AppSensor, here is a good one from Michael Coates, the project lead. Alternatively, here is a very quick video of a demo of AppSensor. So, let’s get started …
AppSensor is an implementation of an idea called application layer intrusion detection. The concept is very simple. While we have controls like intrusion detection at the network layer and web application firewalls at the web layer to detect attacks, these tools work outside the application where they are missing some context. We don’t currently have a good paradigm to represent attack detection and possible response inside an application, unless you completely roll your own. There is actually an implementation of this concept in ESAPI, (see the IntrusionDetector interface) and AppSensor’s implementation can be used as a drop-in replacement for the default handler provided by ESAPI, but more on that later. For now, let’s talk about why you need AppSensor.
So, you do good threat modeling, good security architecture, design, coding, code reviews, white/black box security scans, etc. … great, but you still have security holes. It’s a fact of life that today’s complex applications, and the heavily constrained timelines under which they are built, lead to security holes. If you have an application of any decent size, you are almost assuredly vulnerable to something. You should absolutely continue good secure development practices – these are crucial – but we need more.
Let’s consider those folks that actually end up breaking into our apps. It turns out that attackers vary in how good they are. Some are better than others; some are phenomenal, though the bar has continually been lowered due to automated tools. However, any attacker, bad, good or great, almost always has to try several things in order to successfully break into your app (for many classes of vulnerabilities). If they get in on the first try, they’re either lucky, or your app is so insecure, there’s not much that can help it. So, what if we could differentiate the bad guys before they actually get in? That’s the idea of AppSensor. Let’s assume that it takes an attacker 20 tries to find a field he can manipulate to get an XSS bug, but you can detect that he’s trying to find an XSS bug in 5 tries. Now, we have the advantage – we’ve determined he’s a bad guy, and can respond before a successful attack occurs.
The AppSensor project represents both the concept and implementation of an application layer intrusion detection system. First, a little info (and a few references) about the conceptual pieces. There are 3 basic concepts in AppSensor:
1. Detection
2. Evaluation
3. Response
Detection is the process of actually recognizing that an attacker is performing an attack. This involves adding code (which we’ll show a sample of below) to points that are deemed valid “detection points”. These are points in the code where we know the expected reasonable path(s) a user should be performing, and have a way to detect the user has varied from the path. Consider the case where a user submits a GET request when the form is setup for a POST. That should NEVER happen in a normal circumstance unless the user is doing some modification. A collection of these detection points has been created by the team in order to help you get started in determining reasonable locations to check for attacks.
Evaluation is the process of evaluating all the actual attack detections across the system for all users and determining when it is appropriate to trigger certain response actions. This is, for lack of a better term, the “engine” of the system, and is really behind-the-scenes code for anyone who wants to implement AppSensor. The interface to this would be the threshold setup (shown below)
Response is the activity of actually responding when it is determined an attack has actually occurred. A collection of these response actions has been created by the team in order to help you get started in determining reasonable responses for attacks.
These are the basic components of the system, but in order to really understand the system, feel free to read the book. This was a mammoth effort to document this concept, and as open source projects go, is some of the best documentation available.
My key part in the project has been from the development side. For a quick “getting started” version of using AppSensor that has some good information (I wrote it
), see the developer guide. Here I’ll show the few basic steps to getting going. I’m going to show the setup here as if you’re using OWASP ESAPI in your project. This is by no means required, but since there is already the concept of intrusion detection, it makes life a bit simpler. Also, since ESAPI is a set of distinct controls, you can use some and not others. So, here are the steps:
1. Replace default ESAPI intrusion detector with AppSensor intrusion detector.
ESAPI.IntrusionDetector=org.owasp.esapi.reference.DefaultIntrusionDetector becomes ESAPI.IntrusionDetector=org.owasp.appsensor.intrusiondetection.AppSensorIntrusionDetector
2. Add threshold configuration. There is an appsensor.properties file (see dev guide for details) that you can use to configure thresholds for when an attack is considered to “trigger” a response. Here’s an example configuration for a threshold.
# http://www.owasp.org/index.php/AppSensor_DetectionPoints#ACE2:_Modifying_Parameters_Within_A_POST_For_Direct_Object_Access_Attempts # number of intrusions in a specified segment of time that constitutes the upper threshold - once crossed, it's considered an "attack" IntrusionDetector.ACE2.count=3 # segment of time (in seconds) IntrusionDetector.ACE2.interval=3 # list of actions you want executed in the specified order as the threshold for this intrusion is met - ie. log the first time, logout the user the second time, etc. IntrusionDetector.ACE2.actions=log,logout,disable,disableComponent # some integer - duration of time to disable IntrusionDetector.ACE2.disableComponent.duration=30 # some measure of time, currently supported are s,m,h,d (second, minute, hour, day) IntrusionDetector.ACE2.disableComponent.timeScale=m # some integer - duration of time to disable IntrusionDetector.ACE2.disableComponentForUser.duration=30 # some measure of time, currently supported are s,m,h,d (second, minute, hour, day) IntrusionDetector.ACE2.disableComponentForUser.timeScale=m
3. Add detection points into your code. This is the hardest actual work – it requires finding those places in your codebase where you can check for an attack. This example shows an instance where we’ve decided that 404 requests could be considered an attack. In this case, a single request or even a handful might be legitimate, but dozens or more probably point to a scanner of some type looking for vulnerable code.
//This example snippet might be placed on a jsp that handles HTTP 404 errors.
//When the page is accessed, this code notifies AppSensor that an invalid page request was made.
//Notice that the exception is created, not thrown
new AppSensorException("ACE3", "Invalid request", "Attacker is requesting a non-existent (404) page (" + requestedURI + ")");
So, that’s it – pretty simple. AppSensor is another tool in the toolbelt for the security developer/practitioner. It is an idea that can be implemented in an application fairly easily and with great effect. It has the power to detect and prevent an attack before it is successful, and has the key advantage of context within an application, allowing us to respond to the user that performed the attack.
That’s it for now. I may post more detailed information about AppSensor as the project progresses. For now, feel free to comment here and let me know what you think.
I should briefly mention the other members of the core team: Michael Coates is the project lead, and Colin Watson is another key member of the team.
AppSensor Project Page
AppSensor Book
AppSensor Developer Guide
This article will provide a quick overview of log forging and discuss a couple simple solutions to prevent it.
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.
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.
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.
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.
Ok, well now we’ve been through all the issues listed in the 2007 version of the Top Ten. The new 2010 version is very similar with a couple discrepancies. I may follow up on those couple of issues at a later time. Hopefully you’ve seen through all the articles in this series that ESAPI (specifically the Java version was used) was built to deal with quite a few real security issues that developers face today. This series has shown that ESAPI can be used in almost every instance to either partially or completely remediate a specific issue, and to do it properly. The ESAPI community is thriving, and good things are coming out frequently. New implementations of some controls are showing up. New people are joining. New issues are being tackled. Get involved with this community and make it better. Use the outstanding controls this group has kindly given away, and offer some of your own.
Hopefully this series has been helpful to you in moving closer to secure J2EE development by exposing you to ESAPI and all it has to offer. I’ll be moving on to different topics in the future. Hope you enjoyed this one!
As a reference, all the articles from the series are listed below for easy access.
——————
Part 0: The OWASP Top Ten and ESAPI
Part 1: The OWASP Top Ten and ESAPI – Part 1 – Cross Site Scripting (XSS)
Part 2: The OWASP Top Ten and ESAPI – Part 2 – Injection Flaws
Part 3: The OWASP Top Ten and ESAPI – Part 3 – Malicious File Execution
Part 4: The OWASP Top Ten and ESAPI – Part 4 – Insecure Direct Object Reference
Part 5: The OWASP Top Ten and ESAPI – Part 5 – Cross Site Request Forgery (CSRF)
Part 6: The OWASP Top Ten and ESAPI – Part 6 – Information Leakage and Improper Error Handling
Part 7: The OWASP Top Ten and ESAPI – Part 7 – Broken Authentication and Session Management
Part 8: The OWASP Top Ten and ESAPI – Part 8 – Insecure Cryptographic Storage
Part 9: The OWASP Top Ten and ESAPI – Part 9 – Insecure Communications
Part 10: The OWASP Top Ten and ESAPI – Part 10 – Failure to Restrict URL Access
——————
As a final note, I’d like to make a special request. If you have any requests for something you’d like to see here, an article on a specific topic involving J2EE web security, feel free to comment here or send me an email. My direct contact info is listed on the About page.