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
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.
This article will describe how to protect your J2EE application from Failure to Restrict URL Access attacks using ESAPI and other techniques. As with all of the detail articles in this series, if you need a refresher on OWASP or ESAPI, please see the intro article The OWASP Top Ten and ESAPI.
What does Failure to Restrict URL Access mean? As usual, let’s check in with what OWASP says it is:
“Frequently, the only protection for a URL is that links to that page are not presented to unauthorized users. However, a motivated, skilled, or just plain lucky attacker may be able to find and access these pages, invoke functions, and view data. Security by obscurity is not sufficient to protect sensitive functions and data in an application. Access control checks must be performed before a request to a sensitive function is granted, which ensures that the user is authorized to access that function.” [from here]
Wow, what does all that mean? Well, the Failure to Restrict URL Access (hereafter referred to as URL authz) is simply a failure of performing a subset of authorization. Authorization is a large topic, with many volumes already written on it, but a short overview here will be helpful to the discussion. Authorization is typically described as ensuring a user has access to something, either a business function, data or both. Here’s a simple example:
User Mary makes a request to delete account id 375.
This statement requires authorization verification. Before we look at authorization, it is assumed that the authentication has already been performed, hence Mary is verified to be Mary. Now for the authorization, we must validate that Mary has access to the “delete account” business function and that she can perform that action for account id 375.
There are many, many ways to perform authorization, some better than others. There are 3 basic issues that crop up when dealing with authorization for the developer: security, granularity and maintainability.
The security piece is foundational – is the implementation secure. If a user requests a resource, the authorization should:
1. execute on every configured request (which should be all requests, except possibly static resources available to everyone)
2. allow access if the user has rights to the function and/or data
3. deny access if the user does not have rights to the function and/or data
The granularity piece has to do with flexibility in specifying restrictions about the authorization constraints. Using our example above, the simplest correct authorization would validate 2 things:
1. that Mary has access to the “delete account” function (meaning presumably she could run this function on any data she has access to).
2. that Mary has access to account id 375 (meaning presumably she could run any function she has access to on this data).
A more complex authorization scheme for this same example might provide more granular controls. It may allow Mary to have access to thousands of accounts, and a handful of various functions, but there may be some accounts she has read-only access to, some she can write to, and some she has full access over. Additionally, there may be a limiting feature of time of day, something like Mary is only authorized to perform these functions between 8am – 5pm (normal work hours). Other limits can certainly be thought of as well.
Obviously the second description has more granularity in specifying constraints, but this implementation will also have to be more complex, and more data will have to be captured to provide the matrix of information required to make an authorization decision.
The maintainability piece deals with the complexity of the design, implementation and stored data as mentioned above in the granularity section. The balance between simplicity of implementation and flexibility is an application specific decision. However, some of this complexity can be reduced by using pre-built solutions like ESAPI, as we’ll see shortly.
Ok, now we’ve covered a bit about authorization in general, let’s discuss URL authz in a bit more detail. URL authz is about a user gaining access to a URL that they should / should not have access to. Using the same example above, the request for a business function to delete an account might be a url like:
/myapp/account/delete?id=375
This is how a request is made in a web app, through URL’s. From this request, we know the user is looking to delete an account from the url, and the account id is 375 from the parameter. In order to validate that this is a valid request, we need to make sure that the user should be able to access the delete account URL. There are a couple of locations this could be done: from the referring page, and from the request handling function itself. You must use the latter, and should use the former for user experience. So, if I’m on the view accounts page, and I do NOT have access to delete, I should not even see the link/button for delete – that’s about user experience. However, if my application prevents the link from displaying, but the user were to directly type it in, he would still have access if I didn’t prevent the access from the request handling function as well. This bit of pseudocode will help get the point across:
JSP code
//if user has access to delete
show link to delete page
//else
show nothing
-----------------
in the servlet/action handling the delete request
//get the user performing the request
//get the account id
//if the user has access to delete this data
proceed
//else
throw some error, log issue, possibly respond in some way to attempted "hack"
Both of these checks are important, but the second is vital to protecting the application. Doing the first only is a form of security by obscurity, which almost always provides very little protection. It won’t be long until the user guesses that this url exists, or until he sees another user access it, and then is able to get there.
Ok, so we’ve now described how standard authorization and specifically URL authz works, let’s see a few practical tips and tricks about how to implement it.
1. Think about authorization at the beginning of the application architecture and design if possible. This can make things much simpler down the road. You can come up with a defined naming scheme to follow or any other host of ideas to simplify the task at hand.
2. Always authorize URLs at the time of the request processing (for security), and you should authorize access at the time of providing a link (for uxp).
3. Pen-test if possible – use both automated and manual testing. This can help ensure a decent sampling of urls are not accessible. Even if you can’t do it exhaustively, it will help build confidence in your solution if a subset works. If you can exhaustively test – all the better.
4. Remember included files – these can be forgotten sometimes, but these can often be accessed.
5. Put all your UI files under /WEB-INF, and use a solution that displays your pages by accessing the pages and rendering them to the user. There are various ways to accomplish this, including straight servlets as well as many frameworks (struts, spring, JSF, etc). Having your pages under /WEB-INF prevents them from being directly accessible to the end user per the J2EE spec.
6. Don’t rely on the security by obscurity argument that no-one will know your urls – automated tools can find these, and even intelligent testers often can make educated guesses about urls based on other urls … it’s a good bet that /account/delete exists if /account/view exists.
7. Use an application intrusion detection system (like AppSensor) in order to detect and possibly respond to attacks in production where people are doing things like forceful browsing to pages that don’t exist in your system.
8. If possible, use a tool or framework that already provides a solid authorization design to use for your environment so you don’t reinvent the wheel. There are many tools out there that do this for you, but your mileage definitely varies here. I’ll mention 2 that I’ve used: ESAPI and Spring Security. Spring Security works well for many cases since it’s quite simple and has good integration to Spring itself if you’re already using that framework. ESAPI is certainly more flexible and extensive, but you’ll likely have to do a bit more legwork to get the system hooked up to your application. Once done though, it does offer more features.
Here are the methods in the AccessController interface that is part of ESAPI. These are the methods you would use to perform authorization in your system:
public boolean isAuthorized(Object key, Object runtimeParameter);
public void assertAuthorized(Object key, Object runtimeParameter) throws AccessControlException;
boolean isAuthorizedForURL(String url);
boolean isAuthorizedForFunction(String functionName);
boolean isAuthorizedForData(String action, Object data);
boolean isAuthorizedForFile(String filepath);
boolean isAuthorizedForService(String serviceName);
void assertAuthorizedForURL(String url) throws AccessControlException;
void assertAuthorizedForFunction(String functionName) throws AccessControlException;
void assertAuthorizedForData(String action, Object data) throws AccessControlException;
void assertAuthorizedForFile(String filepath) throws AccessControlException;
void assertAuthorizedForService(String serviceName) throws AccessControlException;
So, in order to accomplish our task of verifying that a user has access to a certain url, you could use the is/assertAuthorizedForURL() methods, or the generic is/assertAuthorized() methods and pass in parameters specifying you want to authorize a URL and the actual URL data. Please note that this may require you write your own AccessController implementation to integrate with your application and configure ESAPI to use it as the AccessController. Alternatively, you could use one of the reference implementations and build your application so that it uses the ESAPI mechanisms to deal with authorization. Either way, ESAPI’s AccessController interface does allow flexibility in performing authorization of methods and data in your application.
So there you have it. URL authz is a subclass of generic authorization in your application. Authorization is an important concept to focus on during the entire development lifecycle, and URL authz is an important implementation detail that you need to get right when building J2EE apps.
Well, that’s it. Hope you’ve found this article helpful. Let me know if you have any questions or suggestions. Feel free to comment.
Other articles in this series:
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
This article will describe how to protect your J2EE application from Insecure Communications attacks using ESAPI and other techniques. As with all of the detail articles in this series, if you need a refresher on OWASP or ESAPI, please see the intro article The OWASP Top Ten and ESAPI.
What does Insecure Communications mean? As usual, let’s check in with what OWASP says it is:
“Applications frequently fail to encrypt network traffic when it is necessary to protect sensitive communications. Encryption (usually SSL) must be used for all authenticated connections, especially Internet-accessible web pages, but backend connections as well. Otherwise, the application will expose an authentication or session token. In addition, encryption should be used whenever sensitive data, such as credit card or health information is transmitted. Applications that fall back or can be forced out of an encrypting mode can be abused by attackers.” [from here]
Insecure communications is an issue any time data traverses a communications path. For many standard J2EE apps, you’ve got a setup like the following you have to worry about:
- client browser -> web server
- web server -> app server
- app server -> DB server
-> LDAP server
-> JMS server
This is a simple but very common setup for J2EE apps. There are many more layers that could be added, and even a few could be taken away. Here’s the point: you need to think about insecure communications at every tier. You could make the argument that the browser -> web server connection is the most important, and I might even partially agree with that since that’s where the most nefarious things tend to live: on the wide open web. Still, the app server -> DB server connection is pretty important due to the data being transmitted. The point is, all the layers are important since important data is moving from point A to point B.
We know we’ve got to protect the data “in transit”, ie. as it moves across the wire, so …
Protecting against insecure communications could take many forms, but in the web app/J2EE world, it primarily means SSL/TLS, so that’s what we’ll discuss here. That’s right, our good old friend SSL/TLS. For the uninformed or if you just need a good refresher, have a look at this great doc produced by the good people at OWASP.
The use of SSL/TLS is not as easy as flipping a switch, as you might hope or think. There are various issues that have to be taken into consideration. I don’t want to simply re-hash all of the recommendations provided by OWASP, so I’ll try to focus on those most commonly seen by the J2EE crowd. (All the issues called out are important, but not necessarily developer-oriented – some are more frequently handled by network/sys admins.)
Most of us know what SSL/TLS does, but in case you don’t, the intent is to encrypt the data as it is in transit between points A and B. Note: There is no protection provided at the endpoints, but the issue at hand is protecting data while in transit, so SSL/TLS fits the bill.
Now that we know we need SSL/TLS, how do we implement it correctly? There are millions of pages dedicated to setting up SSL/TLS, so let’s assume you’ve gone through that and now need to require it for your particular application. There are various ways to do this. Let’s talk about a few.
1. Setup your web/app server to only have an SSL/TLS (https) enabled service listening, ie. no standard http service running, or at least block that port on the firewall. This option is fine if you can do it, but there’s usually a reason you can’t, and in addition, it doesn’t help if anyone ever comes along and adds http back in – at that point – you’re back at square one.
2. The standard Java way is to add a transport guarantee to the web.xml file. The following snippet shows an example.
<security-constraint>
<web-resource-collection>
<url-pattern>/admin/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
This snippet requires all requests that match the pattern “/admin/*” to go over SSL/TLS. If they are requested over standard http, the request will be redirected over https. This is a fine solution if your application is structured in a manner that you can protect the appropriate urls by using simple url pattern matching. If that’s not true, this method can lead to a rather verbose configuration.
3. The ESAPI way of performing this task is also very simple. This can be done by using the assertSecureChannel method as in the following snippet.
//this method can throw an AccessControlException
//uses the current http request - there is an overloaded method that accepts
//a specified http request object as a parameter
ESAPI.httpUtilities().assertSecureChannel();
If this method finds that SSL/TLS is not being used, it does not attempt to redirect you there. Rather it throws an AccessControlException, which can then be caught and dealt with appropriately. If you’d like all of your pages to require SSL, this code could simply be added to a J2EE filter configured to execute on all requests (“/*”).
4. Other frameworks … there are tons of frameworks, or even custom code that could be used to perform this task.
Ok, now we’ve seen a bit about how to require SSL/TLS in the J2EE environment, let’s talk about a few of the relevant gotchas that J2EE folks have to deal with.
1. Make sure you use SSL/TLS between all tiers. Don’t cover just the browser -> web server. Ensure every path is protected.
2. Require SSL/TLS for all login (including page you login from) pages as well as any authenticated pages after login.
3. Use http POST as opposed to http GET for any sensitive information. This is always true, but makes even more sense with SSL/TLS as the POST data is protected by SSL/TLS, but the url is not as that is required to make the request. This means others viewing your request can still see your sensitive data since it’s part of the url.
4. Mark all your user cookies secure: this prevents your browser providing the session cookie to an attacker in the event of an attack that causes you to request a non-SSL/TLS url from the application. If the cookie is not secure, your browser will still happily provide the cookie even if the site doesn’t support http … protect your users.
5. Don’t put any insecure content on your secure pages. This could allow an attacker to “inject” content into the page and have that information presented to a user as if it came over the SSL/TLS connection.
6. Often times it is just easier to protect the entire site with SSL/TLS. This is fine, but be aware of any performance concerns. SSL/TLS does require overhead. It’s gotten pretty optimized over the years, but it will always be slower than http. If you are on a high volume site, think about what data you are presenting, and test both with and without SSL/TLS to verify any performance differences. However, no matter the performance difference, always follow the other rules listed here. Protection of data is better than a slightly faster site (since we are talking about security here :>).
7. Stay educated and patch when necessary. SSL/TLS has been a standard technology for many years now. However, just within the past few months, there have been reasonably large bugs found and resolved. Largely, these bugs have to do with implementation and not design, however you need to stay educated nonetheless.
8. Comply with policy / legal regulations. For some types of data (credit cards and SSN’s for instance), there are legal requirements imposing the use of SSL/TLS to protect the data in transit. These may or may not apply to you, but be sure you know, because failing to meet them could be a very bad thing indeed.
So there you have it. SSL/TLS is fairly well known, but there are some things to look out for when building a site that uses it.
Note: In very recent days, news came out that Robert “RSnake” Hansen and Josh Sokol were able to poke some pretty major holes in SSL. I have not had the time to adequately research their findings, but you should. I do assume, based on the credence of the researchers, that the research is sound, so pay attention. This does however point to the fact that a defense-in-depth approach to security as well as building security in at every layer are best practices.
For some additional background and information on SSL/TLS, see the Transport Layer Protection Cheat Sheet referenced above.
Well, that’s it. Hope you’ve found this article helpful. Let me know if you have any questions or suggestions. Feel free to comment.
Other articles in this series:
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
This article will describe how to protect your J2EE application from Insecure Cryptographic Storage issues using ESAPI and other techniques. As with all of the detail articles in this series, if you need a refresher on OWASP or ESAPI, please see the intro article The OWASP Top Ten and ESAPI.
First, let me start off by saying Crypto is hard, really hard. There are various aspects to cryptographic security, and all of them are difficult to get right. Some examples include creating an algorithm, using the algorithm and key management. Typically, developers aren’t creating algorithms. That is often done by (really smart PhD) mathematicians, and a small set of developers who implement those algorithms. However, many developers do “use” those algorithms to do some type of encryption in their applications. Developers also have to deal with key management.
Let me additionally state here that I am by no means an expert on this topic. I have some background with crypto, but I certainly don’t have a lot, so much of what’s presented here are generally accepted best practices, and don’t necessarily come from my own experience. OK, on to the detail…
What does Insecure Cryptographic Storage mean? As usual, let’s check in with what OWASP says:
“Protecting sensitive data with cryptography has become a key part of most web applications. Simply failing to encrypt sensitive data is very widespread. Applications that do encrypt frequently contain poorly designed cryptography, either using inappropriate ciphers or making serious mistakes using strong ciphers. These flaws can lead to disclosure of sensitive data and compliance violations. ” [from here]
So, this is pretty self-explanatory. If something can go wrong, it will with crypto. There are lots of reasons why this is probably true. First, it’s hard to get right in the first place – there are a lot of moving parts. Second, developers typically don’t understand it as well as other aspects of software. Third, it’s rare. A small number of people have been dealing with crypto for a long time, but it’s only a relatively recent development that LOTS of devs have been impacted by it. Part of this is due to new regulatory constraints that require encryption of some kind for data at rest.
Now that we’ve established that crypto storage is hard, let’s talk about a few common approaches that can help remedy the issues.
1. Stay Educated. This is an important step. Due to the increase in computing power that we gain every year, as well as new cryptanalytic (breaking a crypto algorithm) attacks, the list of “good” algorithms is somewhat of a moving target. Typically, if you’re in the US, NIST (nist.gov) is a good place to check as they set crypto standards. Additionally your workplace may have a set of approved standards that you would need to follow. Also, read books to learn about crypto. You may not be the mathematician coming up with the algorithms, but there is much to learn here that will benefit you.
2. Use good algorithms. This is a follow on to the first point, but it’s important enough to call out separately. Do NOT create your own crypto algorithm unless you’re an expert – it is very difficult to get right. Even the guys at the top of the field tend to create algorithms as part of a team, and those algorithms are generally only accepted as secure after years of analysis by peers. Additionally, do NOT use old, weak algorithms. These could help to a point, but many of them are able to be broken in minutes or even seconds these days. It’s easy enough to use solid algorithms, so educate yourself and make the right choices.
3. Do good key management. This is a broad topic which I don’t even pretend to comprehend fully. There are many possible ways this could work. At the current time, it’s even an active discussion among the ESAPI developers over how they plan to do it. There are various options from just hard-coding a key (DON’T DO IT) all the way up through large commercial systems to do key management for you. Spend some time thinking over your requirements, and make an informed decision.
4. Encrypt credentials. Pretty much every J2EE system connects to a DB, LDAP, web service or some other repository. The credentials to make these connections should be encrypted to prevent easy access to these data storage systems.
5. Don’t store sensitive data if it’s not a requirement. Storing sensitive data is what introduces these complexities. It’s better if you don’t have to worry about them in the first place. Only store sensitive data when there is a firm legal or business requirement.
6. Know your regs. Know your legal and regulatory requirements. There are certain provisions in these requirements that prevent the storage of certain pieces of data EVER. Storing this data not only places additional requirements on your application, it can carry some hefty fines for breaking these laws.
7. Simplify. It’s the old KISS principle. However, when it comes to crypto, it’s certainly true. Do the least you’re required to do in order to store sensitive data securely. The more complex a system, the more difficult it is to secure generally.
8. Store the key/password/data separately. These pieces of information make up your data protection mechanism. Storing them in the same place makes it simpler for an attacker to gain access to all of them. If they are stored separately, an attacker may still gain access to all of them, but it’s more difficult.
9. Use filesystem controls. Operating systems have filesystem access controls for a good reason – so you will use them. Protecting data is a defense in depth task, but protecting the keys, passwords, etc. with filesystem controls locked down so only the appropriate user(s) has access is a best practice measure to help secure your data.
One thing to note here is that I did not add any sample code snippets for this topic. This was intentional. At the moment, the ESAPI encryptor implementation is going through a fairly significant update and code review. There is still some discussion of major changes coming. Either way, ESAPI will provide support to encrypt/decrypt and hash data. The interface to that functionality may change, but the library will provide those features – you can be sure of it.
Well, that’s it. Hope you’ve found this article helpful. Let me know if you have any questions or suggestions.
Other articles in this series:
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