11.05.2009

Is Role Based Access Control dead?

This question has been coming up a lot in different circles lately and it seems like there isn't a great deal of online buzz or conversation about it, so I would like to bring it to the online collective for discussion and debate.

I have contested lately that RBAC (Role Based Access Control) just flat out doesn't work in today's world. There was once upon a time, when applications were much simpler that this concept fit very well in the application security world, but we no longer live in that world.

The problem with RBAC is that it is a big hammer. It is what I like to refer to as an all-or-nothing solution to a problem that deserves a much finer grained answer. To elaborate on this, let me first explain the concept of RBAC.

1. Applications have users.
2. Users need to be be able to perform actions.
3. Actions are associated with Roles that are allowed to perform said actions.
4. Users belong to one or more Roles.

This is a very *simple* solution to the problem of access control in an application, and in simple applications, it works quite well. RBAC is widely supported by vendors and comes built in to most web application containers. It also happens to be the access control mechanism used by most OS vendors (Replace Role with Group and Voila!). There are tons of implementations for J2EE applications such as Spring ACEGI, JAAS, etc.

When you want to check if a user can perform some action you simply use a quick check

   if ( user.isInRole( Roles.ADMINISTRATOR ) ) {
      doAdminStuff();
   }

So what is the problem with this simple, widely supported, very popular means of access control? It's simple really, RBAC has no awareness of the context request for access.

To illustrate this point, consider the following situation.

You have just completed coding a wonderful project management application for Big Humungous Inc. that filled all the requirements, is unhackable, and even has a list of features far exceeding the clients requests. One day you recieve a call that your client is creating a special group of representatives that need to have administrative access to customer accounts that belong to Group A between 2pm and 3pm every Monday, Wednesday, and Friday.

Now you have a problem. A role is an all-or-nothing access mechanism. So you can't just add the users to the Administrator Role, so your only option is to go back into the code and add a new check in the code that says am I in this role, and do I meet all these other requisites to do the requested action. Then you need to implement that code in every place where you would normally ask is the user an administrator?

Now let me introduce to a different approach to Access Control. It goes by many names. Some call it Activity Based Access Control, I call it Context Based Access Control. The concept is simple.

Make your Access Control mechanism aware of context!

There are any number of ways to do this, but I will address that in a subsequent article as this is more about the interface it provides. Adding context can allow you to specify any number of dynamic situation that are taken into account when determining whether a user has access to perform an action. Consider the following:

public interface AccessContext {
   boolean isAllowed( User u );
}

public interface AccessRole {
   // Some methods
}

public interface User {
   // ... Other user'ish stuff
}

public interface AccessController {
   boolean canUserPerformAction( User u, Context c, Action a );
}

public interface Action {
   void performAction();
}

This is a simple outline of how a Context Based Access Control API might look. Now in your code you might have something that looks like this:

   User user = RequestHelper.getUser();
   Context requestContext = RequestHelper.getContext();
   if ( accessController.canUserPerformAction( user, requestContext, new Action( "Delete User" ) );

Of course this is a very simple and open ended example, but it gets the point across rather well and illustrates the ability to solve problems in a manner that allows the AC layer to be as fine-grained or big hammer as it needs to be in any given situation.

To summarize:

1. Role Based Security doesn't address the problems of today's applications.
2. Context or Activity Based Security has the power to address those problems, but there is no force driving it forward.

I have proposed to the ESAPI team that we are in the perfect position to address this problem at the API level. Designing a clean interface that addresses the simple as well as complex control situations is really the difficult part in this concept.

An interesting read if you have a second - it looks like Microsoft had the same idea 2 years ago, too bad they patented it and did absolutely nothing with it.

http://www.freepatentsonline.com/y2007/0143823.html


I would love to hear what the 'verse has to say about this so let's get some conversation going around this topic and see what we can come up with!

8.06.2009

Twitter DDoS'd - Not related to recent activities?

Let me start by saying, "Yeah Right, Twitter!"

Here's the problem; nobody, least of all, Twitter, really knows the extent of the information that was acquired by Hacker Croll a few weeks ago. There is only speculation as to how deep into Twitters infrastructure he got, and only he knows.

Now, just a couple of weeks after the Hacker Croll incident, Twitter suffers from a massive DDoS attack. There are 2 types of DDoS attacks, those that are meant to bring a network down completely, or those that are meant to divert the corporate I.T. guys attention for a period of time while the real work is done on the target service that isn't getting attacked.

If I were Twitter, that's where I would be focusing my attention at this very minute. What services didn't suffer from the DDoS - who accessed those services while the DDoS was happening. Any defiant who has any experience in the field at all will have erased their tracks long before anyone thought to focus on the stuff that didn't go down, and so it is likely, whatever the real purpose of the DDoS was, Twitter will have to sit on their hands until it is revealed or the person behind it slips up.

So, you might find yourself asking, "Well what should you do in a DDoS situation?"

Other's will have different opinions I am sure, but my answer is simple. Focus 50% of your resources on the services that are down and the rest on the services that aren't seemingly affected.

It is always possible this was just some group of $kiddies with a network of zombies just pulling a prank, but given the amount of news around Twitter lately, and the high-profile hacks that have infected their media coverage - I find that highly unlikely.

We will see if I am right soon enough I suppose, but at bare minimum, if I were at Twitter, I would be focusing a lot of attention around performing a full site audit right now and taking inventory of every machine that has access to the internal network, as well as auditing every employee in the organization who was involved directly or indirectly with the fiasco a couple of weeks ago.

What are your thoughts?

8.05.2009

The State of Internet Security - Revisited

In June I wrote a blog on the state of security on the net and I keep hearing the experts saying the same thing that I have said. In an interview with Dan Kaminsky about a recent SSL and DNS Vulnerability, Kaminsky put it out there the same way I did.

"This is our best technology for doing authentication and it failed," he said. "We'll fix it, but it's another sign that we need to revisit how we do the basics; how we do authentication on the internet."

That's exactly it, we need to go back to the drawing board. Why don't we spend some time and money and put all of these experts, and I mean the real experts, the ones who are breaking protocols and smashing the stack every day because they enjoy it, get them all in one place. Why don't we give them a digital whiteboard, all the food they can handle, and let them design a system that works!

Granted, there is no such thing as a completely secure system, but I'll bet that armed with the knowledge that we have today, the tools and a budget, we could come up with something that is a lot closer than a system that was designed before XSS and SQL Injection on the internet were even a twinkle in some $kiddie's parent's eye.

I feel a little bit better now after that rant. What really irks me is that everyone has thought it, most of us have even said it aloud! The system doesn't work. We keep trying to hack fixes into decades old code to account for these new bugs, but it's like putting a brand new Hemi into a 1982 Toyota Corolla - it just doesn't work.

8.04.2009

Synchronizing the HttpSession

This is something that I have heard a great deal of debate over the last 2 years about. The servlet spec was somewhat recently amended to clarify that there is no guarantee that multiple calls to HttpServletRequest.getSession() or HttpServletRequest.getSession(boolean) will return the same object. This holds especially true in containers that return a facade object that wraps around the actual HttpSession object that you are working with, like Tomcat.

Why would you want to synchronize a session anyway?
The answer is pretty simple actually. Consider the following theoretical block of code:

public class WithdrawFundsServlet extends HttpServlet {

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
User u = ESAPI.authenticator().getCurrentUser();
String withdrawAmt = request.getParameter("withdrawAmt");
float amt;
Account acct = session.getAttribute("acct_"+u.getAccount());
try
{
amt = Float.parseFloat(withdrawAmt);
}
catch ( Throwable t )
{
ESAPI.log().info( Logger.SECURITY_FAILURE, "Non-Numeric value passed as Withdraw Amount");
try {
ESAPI.httpUtilities().sendForward(request, response, "/error" );
} catch (AccessControlException ignored) { }
}

// Calling Withdraw will queue a check to be printed and mailed to the customer.
AccountFacade.withdraw( acct, amt );

try
{
ESAPI.httpUtilities().sendForward(request, response, "/success" );
}
catch (AccessControlException ignored) { }

return;
}
}


Now there are a couple things that I will point out that I am sure you will notice if you are paying attention. The first is that yes, this example is using the ESAPI. Call it a shameless plug :). The second is that I am ignoring AccessControlExceptions. This is purely to keep this example scenario short and to the point, and in any production code, you would never want to do this. There would also be some validation code in there as well.

Aside from those things, it looks innocent enough right? Well let's consider this for a second with a scenario.

Joe needs to have a check cut to him from his account at SomeBodiesBank. So he gets online and hits the form for the above servlet. Joe is not that savvy of a computer user, and like most novice internet users will do, he has the tendency to double-click on everything. He fills out the form to withdraw $500 from his account and double-clicks the submit button. So somewhere on the backend, we'll say in the AccountFacade.withdraw method, the software validates that Joe has enough money to cover the check, it discovers he has $750 in his Checking account so everything looks good. But wait a minute, Joe double-clicked remember?

Do you know what happens when you double click the submit button on a form? Well, 2 requests get submitted one after the other. Hmmmmmm.. So now I have 2 requests entering this method at the exact same time, both requests check Joe's balance and discover that he has $750 in his account, so they both queue up a request to print a check for the requested amount. There's only one problem, these are cashiers checks, the bank has withdrawn $1000 dollars (or in some circumstances, maybe only withdrew the original $500 from his account) but Joe ended up with $1000 in cashiers checks!

The checks show up in the mail, and Joe being the responsible individual he is, reports this to the bank. The bank will likely write this off as an anomoly and the bug will remain until one day when Joe is down on his luck and remembers the bug. He finds a program called JMeter and submits 1000 requests to the servlet as fast as he can for $1000 withdrawals. When his 1,000,000 in cashiers checks arrive, he promptly leaves the country and disappears in the backwoods of New Zealand never to be heard from again.

So the moral of the story is that this problem could have been easily avoided simply by adding thread-safety measures to the code. Granted the example cited is extreme and the consequence of the example even more extreme, but I can promise you that something similar to the situation has already happened and even moreso I can guarantee that something similar will happen again.

So, with this knowledge, what is the correct means to add thread safety around manipulating the session. It's quite simple even.


final Object lock = request.getSession().getId().intern();
synchronized(lock) {
AccountFacade.withdraw( acct, amt );
}


Would do the trick in this simple example.

It's important when using synchronization to always lock on immutable objects. It is also important to use the same lock when locking in multiple places where you are working with the same data. Thread-safety is an entire subject on it's own that is will beyond the scope of this blog posting, so I will cut to the chase here.

This is incorrect, and not guaranteed:

synchronized (request.getSession()) {
// do stuff
}


While this method is proven and works:

synchronized (request.getSession().getId().intern()) {
// do stuff
}


Some interesting stats to close out with:

Google Code Search Results found approximately 4000 uses of different ways to say 'synchronized(session)'

The scary part is this was only the first 5 ways I came up with to search for it.