3.22.2012

T5WTPYAFGP - Fix Your URL


At South by Southwest this year, during my talk Defense Against The Dark Arts - ESAPI I covered the "Top 5 Ways To Protect Your Application From Getting Pwnd" [T5WTPYAFGP]. After a couple offline conversations I decided that this would make an excellent series of follow-up blog posts so what follows is the adaptation of that presentation material from that talk. Unlike a lot of other Top-N lists, the goal of this one is not to iterate the flaws, but rather to iterate the solutions.

Additionally each post includes some samples on how you can use ESAPI to implement the solutions discussed.
You can use the navigation below to navigate between each of the posts.

[5] Encrypt Sensitive Information
[4] Become "Big Brother" 
[3] Fix Your URL [Current]

3. Fix Your URL
In the history of dynamic web applications, few things have been more fruitful and more easy than simply changing the value of a parameter on a URL or in a hidden form field. For years we have seen urls that contain something like ?id=1000 which instructs the application to load the data associated with a primary key value of 1000. This isn't rocket science, and it required behavior in most apps, after all it is the very definition of a dynamic web application.

What about a form with a field like this:

<input type="hidden" name="id" value="1000" />

This seems innocent enough, but what if the object on the other side of that id is a sensitive document, or contains sensitive information?

Better yet, what if we change the name of the parameter to accountNumber and the data on the other side of accountNumber contains all of the financial data for the client of a bank? What if that banks name happens to be CitiGroup?

Last year, CitiGroup was the target of an attack that exposed the financial information, including credit card information of 200,000 customers, about 1% of their customer-base - all because of a little problem from the OWASP Top Ten called Insecure Direct Object References. Attackers in this case discovered a parameter that they could simply increment to gain access to user accounts that did not belong to them.

So how exactly do you protect yourself against this problem, I mean we have to have the ability to reference data dynamically and the selection of that data has to come from the client.

Option 1: Data Level Access Control
The best solution to this problem is to implement some kind of data level access control policy. This can be implemented in a number of ways from Row-Level Security in the database layer to implementing an application layer check. Creating and implementing a data level access control policy is a difficult and time consuming task and is extremely hard to get right.

In my SXSW talk I glazed over this approach a little, mainly because it is a field full of many rabbit-holes just waiting for some poor unsuspecting speaker to tumble in. Below are just a few of the potential solutions and some high level analysis of each approach.

Database Row-Level Security
Row-Level and Cell-Level Security are a bit of an ingenious idea that has grown in popularity over the last several year - the fundamental idea is that you limit the data accessible to the session user. While Oracle and SQL Server have implemented this type of functionality natively within their products and documented it somewhat profusely, it isn't quite as straight-forward in MySQL - so that is where we will focus for the purpose of this post.

There are 2 key elements to implementing a Row-Level Security implementation at the database layer:

  1. Federate User Identity to Database Layer
  2. Extensive use of Views
The idea here is that the view acts as the Policy Enforcement Point for the data being requested by the User. There are two approaches to defining the policy for data - add a column to the table, or have a central policy table that is joined in the view definition. I like to opt for the second option simply as a matter of maintainability. 

Envision you have the following table:

create table account (
   id         bigint not null auto_increment,
   type       int not null,
   name       varchar(64) not null,
   primary key (id) 
) engine=InnoDB;

Perhaps you create a policy table (and support tables) with the following schema:

create table rls_policy (
   id         bigint not null auto_increment,
   user_id    bigint not null,
   data_id    bigint not null,
   data_type  int not null,
   read       int(1) not null,
   write      int(1) not null,
   create     int(1) not null,
   delete     int(1) not null,
   primary key (id),
   foreign key (user_id) references user(id),
   foreign key (data_type) references data_type(type),
   index (user_id, data_id, data_type)
) engine=InnoDB;

create table data_type (
   type        varchar(256) not null primary key
) engine=InnoDB;


Now you need to create a view:

create or replace view user_accounts (
   id,
   type,
   name
) 
AS
   select acct.id
        , acct.type
        , acct.name
     from account acct
        , rls_security rls
    where rls.user_id = @app_user_id
      and rls.data_type = 'account',
      and rls.read = 1
 order by 3 asc;

The final step is to instruct your application to set the app_user variable when a connection is checked out and clear it when the connection is returned (assuming you are using a connection pool)
public class RowLevelSecurityConnectionCustomizer extends AbstractConnectionCustomizer {
    @Override
    public void onCheckOut( Connection c, String pdsIdt )
    { 
        User currentUser = ESAPI.authenticator().getCurrentUser();
        try {
            PreparedStatement ps = c.prepareStatement("SET @app_user=?").setInt(Integer.valueOf(currentUser.getAccountID());
            ps.execute();
        } catch (Exception e) {
            // Don't blindly catch exceptions and take no action in production, please for the love of all that is good and holy.
        }
    }
    
    @Override
    public void onCheckIn( Connection c, String pdsIdt )
    { 
        try {
            c.executeUpdate("SET @app_user=NULL");
        } catch (Exception e) {
            // Handle the error
        }
    }

The code sample is not guaranteed to compile and work (I don't remember the last time I interfaced directly with JDBC), but is simply to illustrate the idea.

Now when you would normally query the accounts table, you should be querying the view instead. The results returned in a select * from user_accounts; will result in a subset of the data scoped to the currently logged in application user. This example can be extended even further using triggers and update-able views to add policy enforcement to create, update and delete actions as well.

Application Layer Data Access Control
Another approach is to perform data access control in your application, which has been the standard approach to this problem for some time. The ESAPI implementation ships with a reference implementation of the AccessController which illustrates an example of how to build a data access controller and access control policy.

Once you have your policy configured, you can simply invoke the ESAPI Access Controller to make your policy decisions.
ESAPI.accessController().assertAuthorized("AccessAccountInfo", account);

Option 2: Indirect Object Reference Map
Creating a data level access control policy and implementation is a time consuming and daunting task, and may not make sense for every situation. When Jeff invented the ESAPI he understood and realized this so he created an object that if used correctly would offer a solution to the problem of direct references and offer some deny by default access control to data as well. Using this object is very simple, the idea is to populate the Map with all the data available to the application user first, then refer to each piece of data be it's indirect key rather than it's primary key.

What you end up with is something similar to this (continuing on our accounts example from above)

List<account> accounts = AccountService.fetchAccounts();
AbstractAccessReferenceMap<account> accountReferenceMap = new AbstractAccessReferenceMap(accounts.size());
for (Account a : accounts) {
   accountReferenceMap.addDirectReference(a);
}

session.setAttribute("accounts", accounts);
session.setAttribute("accountsRef" accountReferenceMap);
And a view layer that looks something like this:
<%
   List<Account> accounts = ESAPI.httpUtilities().getSessionAttribute("accounts");
   AbstractAccessReferenceMap<Account> accountRefs = ESAPI.httpUtilities().getSessionAttribute("accountRefs");

   for (Account a : accounts) {
%>
<a href="http://draft.blogger.com/view/account?accountID=<%= accountRefs.getIndirectReference(a) %>">View Account <%= a.getName() %></a>
<% } %>
Which leaves you with a URL that looks something like this:
http://my.company.com/application/view/account?accountID=5JtjyJA573JsJ48732Kkojnv
As you can imagine, this makes it extremely unlikely that an attacker would be able to guess the reference to your account (especially since it isn't a static value and is changing every time the list of accounts is built up)
To add a inferred level of data access control to this strategy, you should populate the list with only accounts that are owned by the application user.

So there you have it, your level of risk should determine which approach you take to solving this issue, but the goal should always be the same - don't be like CitiGroup (or one of the countless other thousands of applications that do the same thing)

Stay tuned for tomorrows post for #2 - Validate User Data!

3.19.2012

T5WTPYAFGP - Become Big Brother


At South by Southwest this year, during my talk Defense Against The Dark Arts - ESAPI I covered the "Top 5 Ways To Protect Your Application From Getting Pwnd" [T5WTPYAFGP]. After a couple offline conversations I decided that this would make an excellent series of follow-up blog posts so what follows is the adaptation of that presentation material from that talk. Unlike a lot of other Top-N lists, the goal of this one is not to iterate the flaws, but rather to iterate the solutions.

Additionally each post includes some samples on how you can use ESAPI to implement the solutions discussed.

You can use the navigation below to navigate between each of the posts.

[5] Encrypt Sensitive Information
[4] Become "Big Brother" [current]
[3] Fix Your URL

4. Become "Big Brother"
As much as "Big Brother" irritates and/or scares the pants off of us in the real world, it is your responsibility to take up this mantle for your application - or better yet, have the application do it for you all by itself!

Intrusion detection and prevention systems are a long accepted means of detecting and neutralizing threats to networks, but there is a common weakness that they all have in common - they are network devices. As a network device they have no context in the application and can only provide a pattern-based blacklist approach to protecting your web applications. While this is a valuable piece of the overall security puzzle, what is lacking is a way for the application to monitor and respond to attacks. The key to implementing this protection is to teach your application to understand user behavior.

What is User Behavior?
To understand user behavior all you have to do is understand how your application is intended to be used. If a user deviates from the happy path by trying to subvert or bypass logic that you have in place then they are exhibiting bad user behavior. However, no user is perfect and everyone occasionally makes mistakes. This is the primary purpose of thresholds - that is, how many times, or how much a user is allowed to deviate from the happy path before they are exhibiting bad user behavior.

As an example, let's take the log in functionality of an application. Logging in a a typical piece of functionality that exists in just about every dynamic web application in the world.

A typical flow chart for the log in process may look similar to this:
There are a lot of user behaviors that we can extrapolate from this process flow. Here are a few of them:

  1. Behavior: Anonymous User reaches (A) more than n times without reaching (C)
    Reaction: [1] notify admin of DoS - [2] ban user ip for n-minutes
  2. Behavior: Anonymous User reaches (D) more than n times with n different usernames
    Reaction: [1] notify admin of Brute Force - [2] ban user ip for n-minutes
  3. Behavior: Anonymous User reaches (E) after times reaching (G)
    Reaction: [1] notify admin of Brute Force/DoS - [2] ban user ip for n-minutes
Notice that in defining the behaviors, we are not altering the flow of the application itself, we are instead detecting conditions across the process flow and reacting to them. This is the true power of application layer intrusion detection and prevention. 

Once we have identified our user behaviors, we can start to educate our application on how to respond to these conditions. By design, to enable intrusion detection in your application, the only requirement is to configure it to be enabled in your ESAPI.properties file. Simply set the IntrusionDetector.Disable property to be false and you are in business. Once intrusion detection is enabled in your application, any exception that extends the EnterpriseSecurityException will raise an event that the intrusion detector can be configured to respond to.

In the ESAPI.properties file you will find a section for IntrusionDetection with a sample configuration for events. You can add custom events here and configure what actions should be taken as well as thresholds for those events.


Introducing AppSensor
Some friends at OWASP took the ESAPI Intrusion Detector and some ideas that they had and built one of the most powerful application layer intrusion detection and prevention components available today. This project, called AppSensor - is built on top of ESAPI so it integrates seamlessly with ESAPI and provides fantastic protection to your application. I highly recommend using AppSensor for anything other than the most basic of intrusion detection and prevention needs.


AppSensor builds on the ESAPI Intrusion Detection component to integrate a state of the art application layer intrusion detection solution that is "ESAPI-Aware" - that is, it is aware of and interacts with various ESAPI components.

What Does it all Mean?
To some it all up - it is your right and your responsibility to ensure the safety of your clients and partners while they are using your applications. Understanding user behavior and recognizing key indicators is the key to stopping attackers before they can attack you and your users and the key to understanding user behavior lies in establishing a flexible application layer intrusion prevention solution.

Stay tuned for #3 in this series - Fix Your URL.

3.18.2012

T5WTPYAFGP - Encrypt Sensitive Information

At South by Southwest this year, during my talk Defense Against The Dark Arts - ESAPI I covered the "Top 5 Ways To Protect Your Application From Getting Pwnd" [T5WTPYAFGP]. After a couple offline conversations I decided that this would make an excellent series of follow-up blog posts so what follows is the adaptation of that presentation material from that talk. Unlike a lot of other Top-N lists, the goal of this one is not to iterate the flaws, but rather to iterate the solutions.

Additionally each post includes some samples on how you can use ESAPI to implement the solutions discussed and gives us the opportunity to dive into each area a little deeper than we were able to in a one-hour presentation.


You can use the navigation below to navigate between each of the posts.

[5] Encrypt Sensitive Information [current]
[4] Become Big Brother
[3] Fix Your URL

5. Encrypt Sensitive Information
Number five on our list is to encrypt sensitive information. To understand this one we first need to define what actually constitutes sensitive information.

Most organizations that store credit card numbers are (hopefully) storing those credit card numbers in an encrypted format already, but what about the rest of the information that is stored. Think about your own organization or application - what information do you collect from your users?

According to published information, anything that is personally identifiable information, financial information, or medical information is to considered sensitive data and should be treated accordingly. Any organization that has to deal with standards verification will generally check the box for storage of sensitive information as long as that information is stored on an encrypted volume. This protects your customers from physical theft but what about run-time theft, which accounts for most of the largest breaches that occurred last year.

The key is to examine the risk for your application, determine what information would be damaging to release for your customers, and encrypt that data at rest. A lot of organizations simply don't want to incur the performance penalties of performing encryption and decryption of client data but some things are simply too important to ignore.

There are a number of ways to help mitigate the performance impact of using encryption in an application  and we will cover a few of them in this post.

The important thing is that once you have encryption configured (ie you have selected a provider and algorythm) actually performing the encryption and decryption of sensitive information is incredibly simple.

// Populate User Object from Request
// ...
// Encrypt Sensitive Information
CipherText encryptedSSN = ESAPI.encryptor().encrypt(new PlainText(userInfo.getSSN()));
userInfo.setSSN(new String(encryptedSSN.asPortableSerializedByteArray());
// Persist User Object
// ...

To decrypt the data is just as simple.
// Retrieve persisted User Object
// ...
// Decrypt Sensitive Information
CipherText encryptedSSN = CipherText.fromPortableSerializedBytes(user.getSSN());
PlainText decryptedSSN = ESAPI.encryptor().decrypt(encryptedSSN);
userInfo.setSSN(decryptedSSN.toString());
// Prepare User Object for use in application
// ...

Of course this can be abstracted into a service, added as an annotation processor in your persistence layer, and altered to be used in a more generic form that meets your specific platform needs. Additionally, depending on the type of information you are dealing with and the perceived risk of that information being leaked - it may make sense for the data to be encrypted all the time until it needs to be viewed or altered on the front end. This approach can also increase performance of the encryption and decryption because you are only ever performing this step when it is needed.

A comprehensive design is a little beyond the scope of this post, but when I do design I like to envision the end goal - that is what will the object I am protecting look like when I am done. To take the concept of the UserInfo object - here is what I envision as the end results:


public class UserInfo implements Serializable {
   private final static long serialVersionID = 1L;

   private Long id;
   private String username;

   // This field will be stored in-memory and persisted as a hashed value using SHA-256 
   @Sensative(type=SensitiveDataProtection.Type.HASH,
              algo=SensitiveDataProtection.Algo.SHA256
              mode=SensitiveDataProtection.Mode.RUNTIME)
   private String password;

   // This field will be stored in-memory and persisted as an encrypted value using the SecretKey "UserData.SSN" for encryption and decryption
   @Sensitive(type=SensitiveDataProtection.Type.ENCRYPTED,
              key="UserData.SSN",
              mode="SensitiveDataProtection.Mode.RUNTIME)
   private String ssn;

   // This field will be persisted as an encrypted value using the Master SecretKey but will be stored in-memory as a PlainText representation
   @Sensitive(type=SensitiveDataProtection.Type.ENCRYPTED,
              mode=SensitiveDataProtection.Mode.PERSIST)
   private String address;
}


This looks pretty simple to implement for a developer and seems to address a lot of design needs, particularly the need to apply encryption only at the point where it is required. Annotations aren't for everyone however, so how can we accomplish a similar design goal without using Annotations?

public class UserInto implements Serializable {
   private final static long serialVersionID = 1L;

   private Long id;
   private String username;

   // This field will be stored in-memory and persisted as a hashed string
   private HashString password;
   // This field will be stored in-memory and persisted as an encrypted string
   private CipherText ssn;
   // This field will be persisted as an encrypted string
   private PlainText address;
}


This example relies on the usage of data-types to specify the behavior of the data. While this breaks some rules in the world of design, it illustrates a possible solution to the problem.

Now do not be fooled into thinking that these solutions are simple to implement, they aren't - however the benefit of centralizing a standard control to perform this work is that you only have to write it once, you only have to maintain it in one place, and every developer of your application doesn't have to understand how the process works, just that it does.

In closing, here are each of the steps you should perform to address this problem and resolve it.

  1. Identify sensitive data in your application
  2. Design and implement a standard and centralized control
  3. Apply encryption to sensitive data in your application
Stay tuned for #4 on our top 5 list "Become Big Brother"!

3.15.2012

SXSW - Defense Against the Dark Arts

So I just arrived back home after a great time in Austin, TX for South by Southwest Interactive where I spoke about ESAPI. I have given several versions of this talk in various forms over the last couple years but this is the first time I have ventured outside of the security community to get this information in front of a different audience. When I submitted the talk for consideration, I really didn't have high expectations of the talk getting picked - and when I got notification that some other talks had cancelled and they had selected the talk for SXSW I was not only extremely excited but, incredibly surprised! I was excited for a lot of reasons, as a musician I have wanted to attend SXSW for many years; as a public speaker I was excited to have speaking at such a large and respected event under my belt and as a security evangelist I was excited to put this material in front of a new and entirely different audience.

As I got my confirmed time slot I was a little put off. I was to give the last presentation of the interactive conference at one of the auxiliary campuses. As expected, there was a number of people that were interested in the talk, but either couldn't make the time slot or didn't want to travel to the venue for the talk. Additionally, the room was the largest at the venue - combined with the smaller draw I was concerned that I would start losing the people that had made the trek.

I was pleasantly surprised at the immediate interaction with the small audience and it turned out to be a very great intimate presentation and conversation with a very interested party. The questions and feedback from the audience was fantastic and even though their was about a 50/50 split of technical and non-technical people present everyone seemed to follow and participated in the conversation.

There were a few lessons learned from this experience - the most important was that at a conference the size of SXSW it is important to do plenty of your own promotion for your talk. I was ill-prepared for doing a great deal of my own promotion and quickly found myself wishing I had prepared a handbill that I could give out to all the people that I was talking to about the presentation while wandering around the trade show and parties. Most everybody that I spoke with seemed interested in the talk and asked questions about it - most of them even expressed interest in attending the talk, but when there are 20-30 talks scheduled at the same time throughout some 5-7 venues throughout downtown Austin, unless there is something that I can hand them to remind them to add the talk to their personal schedule it passes from memory quickly due to the sheer amount of conversations had. I also found myself wishing that I had made arrangements to have the talk video-recorded. I was initially under the impression that all interactive talks were being video recorded but found out that was not the case.

The SXSW volunteer staff was awesome, while in the green room we had access to technical staff and logistics staff to make sure that we had everything in order for our presentation with plenty of time to spare so there was no last minute scrambling. Any questions that they could not answer themselves were quickly answered when they could make a quick phone call.

All of the presentations will eventually be on the interactive podcasts page on sxsw.com - as soon as a link becomes available I will update this post with that link. In the meantime, the slides for the presentation are available online - and a paper with some details to accompany the slides will be available tomorrow.

Presentation Podcast: [Coming Soon]
Presentation Slides: http://portal.sliderocket.com/BLXKW/ESAPI
Presentation Paper: http://yet-another-dev.blogspot.com/p/datda.html

In conclusion, this was an extremely rewarding and humbling experience and has shown me that there are people outside of the security and OWASP communities that are thirsty for this information. I eagerly anticipate my next opportunity to present secure development and ESAPI to more and more communities.