March 29th, 2012 by Lincoln Baxter III

Is your web application secure? HTTP attacks are real, and dangerous

According to a recent research paper by the Aspect Security Group, entitled The Unfortunate Reality of Insecure Libraries, “Eighty percent of the code in today’s applications comes from libraries and frameworks, but the risk of vulnerabilities in these components is widely ignored and under appreciated. A vulnerable library can allow an attacker to exploit the full privilege of the application, including accessing any data, executing transactions, stealing files, and communicating with the Internet. Organizations literally trust their business to the libraries they use.” When validating user input from forms and exposed services, we often ignore the URL or think to ourselves, “that information is validated later, it’ll be fine,” but when hacks like the following start turning up – in common web-frameworks – it’s time to start thinking seriously about URL validation. Fortunately, it’s easy to accomplish using a number of methods, but first, let’s look at how these attacks work.
You can request a copy of the security research paper from Aspect Security’s website.
If you look at the attacks sited as examples in the Aspect Security report, you’ll see that both use the URL as the attack vector, or point of access, and both use the execution of Runtime.getRuntime().exec("system command"), which gives the ability to run any native system command available to the user under which the Java Virtual Machine (JVM) is running; once you are running code on the host system, as the article explains, the potential threat exists of losing control of the server entirely. The first example is Struts 2 – still a popular framework in many places. I found it rather interesting that two of the top three recent security exploits used web-application URLs as a vector of attack, and this came at a timely moment for me, the day I was to present “Security and Usability: URL-rewriting for the next-generation web-user” at the Philadelphia Java User’s Group, a talk in which I discuss the vulnerabilities of URLs, and the risks of improper (or missing) URL validation. I quickly jumped to incorporate relevant pieces of information in my talk.
The next example, surprisingly enough, is applications that use the Spring Expression Language (EL). I wouldn’t be too shocked if this problem actually extends to most EL implementations at the time when this exploit was discovered. After doing a bit of digging, JBoss Seam suffered from a similar vulnerability, and has subsequently been updated to close the gap; I’m sure Spring has done the same, but there are still compromised versions of these frameworks running on live servers across the world.
The last vulnerability was related to Apache CXF, a framework for creating flexible, you guessed it, mostly URL-based web-services. The advisory did not directly explain the vector for this exploit, but if anyone knows, I would love to hear how it worked. (Please add a comment!)

How can we protect ourselves?

This leads to the obvious question: if the frameworks we are using may have inherent insecurities, how can we patch the holes and lock down a potentially vulnerable application? Also, how can we do this without modifying potentially sensitive application code or business logic? The answer is simple – we can apply validation at the URL level, either using Apache (or another Proxy-based solution,) or using a URLRewriteFilter such as [[Rewrite]], an open-source solution from OCPsoft. The principle is simple. If we scrub as many possible URLs in our application for characters that we are certain should never be used, then we can effectively reduce the risk that someone might be able to inject and execute code in our application. URLs are not the only vectors for attack, so we’ll also take a look at how to secure additional forms of user input.

Secure the URL

For the following examples, we will assume that we already have the Rewrite framework installed in our application, but if you need to install it, it’s as simple as adding one JAR file to your project: Install Rewrite. Once this is done, we will start to craft our Security rules.
You can also use a URL-rewriting framework of your choice, but you will need to “convert” this configuration to your framework’s configuration.
The first thing we will do is ensure that all traffic to our website is blocked by Rewrite. This is done by adding a very simple rule, which intercepts traffic in the inbound (requested) direction, and asserts that the request must have come from an internal source (via a Servlet Forward,) otherwise the request will be blocked by returning the HTTP 404 "Not found" error code. We also set a low-enough priority so we can be certain that no other providers will execute first.
SecurityRewriteConfiguration.java
public class SecurityRewriteConfiguration extends HttpConfigurationProvider
{
   @Override
   public Configuration getConfiguration(ServletContext context)
   {
      return ConfigurationBuilder.begin()

               /*
                * Block any in-bound request not forwarded 
                * from within the appication itself.
                */
               .defineRule()
               .when(Direction.isInbound().andNot(DispatchType.isForward()))
               .perform(SendStatus.error(404));
   }

   @Override
   public int priority()
   {
      /*
       * Providers with lower priority are executed first.
       */
      return -1000;
   }

}
Simple enough. Now that we’ve blocked all external traffic to our site, we need to start allowing legitimate traffic back in; otherwise, our site will not be of much use to anyone. We do this by creating a rule that inspects the inbound URLs and checks to make sure that only pre-approved characters are used – meaning we know what a secure URL should look like, and if it contains characters we’ve dubbed as “not secure”, then we aren’t going to accept it. You’ll need to choose acceptable characters to meet your website’s requirements, but if you are not doing anything to fancy with your URLs, then we can expect that only a reasonable few special characters will be required.
SecurityRewriteConfiguration.java
@Override
public Configuration getConfiguration(ServletContext context)
{
   Constraint<String> selectedCharacters = new Constraint<String>() {
      @Override
      public boolean isSatisfiedBy(Rewrite event, 
                            EvaluationContext context, String value)
      {
         return value.matches("[a-zA-Z0-9/:&?.-=_+]*");
      }
   };

   return ConfigurationBuilder.begin()

            .defineRule()
            .when(Direction.isInbound()
                     .andNot(DispatchType.isForward())
                     .and(Path.captureIn("path"))
                     .and(URL.captureIn("url")
                         .where("url").constrainedBy(selectedCharacters)))
            )
            .perform(Forward.to("{path}"))

            /*
             * Block any in-bound request not forwarded by our previous rule.
             */
            .defineRule()
            .when(Direction.isInbound().andNot(DispatchType.isForward()))
            .perform(SendStatus.error(404));
}
Congratulations! We’ve now secured our URL paths from many types of malicious attacks including those used against Struts, Spring, and Seam. This is a valiant step forward, and it was as easy as 10-15 lines of code. We are, however, still missing an important part of the story.

Secure all HTTP parameters

The URL of our application may now be much more secure for GET requests and query-parameters, but we haven’t done anything about our HTTP POST parameters. Without securing these, any inputs from HTML <form> will be vulnerable (or if people just start sending us random requests,) and it’s easy to add this support using another few conditional statements in our configuration. We need only use the RequestParameter condition to inspect the value of any provided HTTP parameters (including query-string GET and form POST parameters.) Notice that we also use .orNot(RequestParameter.exists("{}")), which ensures that having no parameters is still an acceptable scenario.
Add validation of HTTP parameters
.defineRule()
.when(Direction.isInbound()
         .andNot(DispatchType.isForward())
         .and(Path.captureIn("path"))
         .and(URL.captureIn("url")
                   .where("url").constrainedBy(selectedCharacters))

         .and(RequestParameter.matchesAll("{name}", "{value}")
                  .where("name").constrainedBy(selectedCharacters)
                  .where("value").constrainedBy(selectedCharacters)
                  .orNot(RequestParameter.exists("{}")))
)
.perform(Forward.to("{path}"))
So… Coffee’s still hot. What next?

Customize the rules

While this global rule may work for a large number of cases in our application, it’s worth noting that you need not open up all URLs using a single rule. We could just as easily have defined custom rules to match certain or specific addresses in our application. For instance, if we want to allow more characters in a password field, we can add an additional rule, which only applies to our Login page, and opens up this functionality.
Notice how we have added the .where("name").matches("(?!password).*") statement in order to apply our constraints to all fields except the password, and we’ve only exposed this on POST requests, via the .and(Method.isPost()) statement.
Exposing the login page form submission
.defineRule()
.when(Direction.isInbound()
         .and(Method.isPost())
         .andNot(DispatchType.isForward())
         .and(Path.matches("/login"))

         .and(RequestParameter.matchesAll("{name}", "{value}")
                  .where("name").matches("(?!password).*").constrainedBy(selectedCharacters)
                  .where("value").constrainedBy(selectedCharacters)
                  .orNot(RequestParameter.exists("{}")))
)
.perform(Forward.to("/login"))
However, in this scenario, it may actually be simpler just to write our own Condition to perform the restriction we want. Writing custom conditions is easy, and means that you have full control over the Rule matching algorithm.
Writing a custom Condition
.and(new Condition() {
   @Override
   public boolean evaluate(Rewrite event, EvaluationContext context)
   {
      // TODO Return true if the condition is satisfied
      return false;
   }
})
But there’s more…

Secure the HTTP headers

If we really want to do our diligence, we also need to secure the HTTP headers as well – this can also be done using a URL-rewriting framework. It will look very similar to the way we secured HTTP request parameters.
Securing the HTTP headers
.defineRule()
.when(Direction.isInbound()
         .and(Method.isPost())
         .andNot(DispatchType.isForward())
         .and(Path.captureIn("path"))

         .and(Header.matchesAll("{name}", "{value}")
                  .where("name").constrainedBy(selectedCharacters)
                  .where("value").constrainedBy(selectedCharacters)
                  .orNot(Header.exists("{}")))
)
.perform(Forward.to("{path}"))

Conclusion

Enough code, more talk. This proof of concept work shows how it is possible to secure, or at least improve upon the existing security of, existing Java web-applications. It also shows how a few simple rules can be used to facilitate securing many pages, or very specific pages, and the important thing to remember is that no matter what web-framework you are using – you can still add additional validation and security on top using URL-rewriting techniques. Keep in mind that you should implement security at all levels of your application. For securing your business methods, Apache DeltaSpike Security will be very helpful for CDI-based applications, Seam Security and Spring Security also have good solutions. Do not consider this article to be “the answer” for security. It is just one option, and one additional technique you can use to protect your sensitive applications and information. If you would like to learn more about the OCPsoft Rewrite framework, you can visit the project homepage, or check out the sources on GitHub. There are [[Calendar|Regular development meetings]] held every Monday at 2pm EST (GMT+5) on Google Hangout.

Posted in OpenSource, Rewrite

10 Comments

  1. Hi,

    great post. One more thing to take care of. Even if you application is the securest possible you still would need to do a lot more hardening on different other levels.
    E.G. Appserver, Network, DB …
    I wrote up a little hardening guide for GlassFish a few months back .. might be useful to anybody interested in security.
    http://blog.eisele.net/2011/05/securing-your-glassfish-hardening-guide.html

    – M

    1. Thanks Markus, Very nice article!

  2. Mehdi says:

    Hi Lincoln
    Very nice article.
    I think there is no clarification between Prettyfaces and Rewrite use cases.
    Which one is good for which use cases?
    I have an enterprise JSF(Primefaces) and CDI based project. Which one should I use.

    1. PrettyFaces 4 will use Rewrite as a core. Currently PrettyFaces 3 does not use Rewrite, but in theory, both can be used together. (I would try not to.)

      Depending if you want easy configuration for URL-mappings, injections, and page actions, PrettyFaces 3 may be a better option for you at the moment, but Rewrite provides much more control over the entire lifecycle.

  3. […] Baxter III asks Is your web application secure? HTTP attacks are real, and dangerous: According to a recent research paper by the Aspect Security Group, entitled The Unfortunate […]

  4. David Jorm says:

    Nice article! A couple of things:

    * You’re filtering GET and POST parameter inputs, but what about other vectors? HTTP Headers come to mind.

    * The filtering you’re doing does not seem to be canonicalizing the strings, unless I’m missing something. An attacker could just URI-encode the string and circumvent the filtering.

    1. Hi David,

      You’re correct about the HTTP headers! I’ve added a short section describing this as well.

      Regarding canonicalization – that’s one approach. I don’t think this approach is suceptible to URI encoded attacks, though, because these rules will block on any ‘%’ characters. So URI encoding is disallowed by default, and be met with the 404 page.

      ~Lincoln

  5. JavaPins says:

    Is your web application secure? HTTP attacks are real, and dangerous…

    Thank you for submitting this cool story – Trackback from JavaPins…

  6. Hanynowsky says:

    Very useful article. Using today PrettyFaces for URL Rewriting.
    I was considering using Rewrite for URL validation in order to add security but I am against adding it along with PrettyFaces.
    Looking forward to using PrettyFaces 4.

    Exellent Job Guys.

  7. […] Is your web application secure? HTTP attacks are real, and dangerous […]

Leave a Comment




Please note: In order to submit code or special characters, wrap it in

[code lang="xml"][/code]
(for your language) - or your tags will be eaten.

Please note: Comment moderation is enabled and may delay your comment from appearing. There is no need to resubmit your comment.