Week of War on WAF’s: Day 4 — Closer to the code
[ Andre and Marcin ]: For today’s post, we have a guest blogger, Rohit Sethi. We asked Rohit to do this guest post because we feel that his research, along with co-worker, Nish Bhalla, has been influential at solving some unique application security problems. We met Rohit and Nish at Shmoocon 2008 as fellow speakers — their talk was our undisputed favorite as they did an outstanding job at presenting and conveying their message.
Their talk, Using Aspect Oriented Programming to Prevent Application Attacks [PDF] discussed how to take an existing application and add input validation (XSS, SQL Injection, etc), strong error handling, and access controls without ever changing the existing source code. We strongly encourage you to check out their work. Rohit also has a fabulous post for us today on WAF vs. Aspect Oriented Programming — a warm welcome and big thank you to the great work he’s done here! [ Cheers, TS/SCI Security blog ]
Web Application Firewalls vs. Aspect Oriented Programming
As a concept, the WAF (Web Application Firewall) is brilliant. It extends an application’s trust boundary to include input from otherwise dubious sources. Fundamentally, it externalizes many security concerns away from the application’s core logic. What makes the concept of WAF so appealing is that the technology addresses security as a “cross-cutting concern”; a part of the application that is pervasive across the code base yet rarely relates directly to the business logic. Other cross-cutting concerns, such as transactional management, coarse-grained error handling, and logging also end up diluting the code within an application away from core business logic (also known as “code scattering”). On a more practical level, WAFs can implement the security cross-cutting concern without changing existing source code — meaning we can implement WAFs quickly and avoid destabilizing the application through code modification.
In practice, WAFs often suffer from a few drawbacks. In many organizations, WAFs are handled by an infrastructure or security team who are not intimately familiar with the applications that they’re protecting. This often (though not always) ends up becoming an elaborate blacklist filter for malicious characters. Blacklisting is never ideal, but in the case of WAFs the danger is exasperated. The WAF and the application it’s protecting are two different technologies. That means canonicalization attacks, such as sending malicious characters in illegal multi-byte or malformed UTF8 character sequences, may pass through the WAF interpreted one way and attack the application interpreted another way. This interpretation delta with disparate technologies is the same sort of problem that worsens attacks such as HTTP Response Splitting and HTTP Request Smuggling.
Is there a way for developers to protect their own applications without having to modify source code? Can you modularize the security cross-cutting concern without relying on an external application/appliance? Yes — with Aspect Oriented Programming (AOP). At a very high-level, AOP is like applying Servlet Filters anywhere in your code (for more details, please see the article I wrote for SecurityFocus). Using the flexibility of languages like AspectJ, developers can choose the most appropriate layer (i.e. application design layer, not OSI stack) to protect their applications. A critical feature is that you are working with data as the rest of the application server sees it — in its most canonical form. Unlike Servlet filters, AOP can be used to protect other interfaces like SOAP interfaces, RMI connections, etc. Developers can also to choose to delve much deeper in the code and protect, say, the basic Value Objects representing the application’s data types by intercepting calls to the setter methods.
With a WAF, you can protect against SQL injection by stripping out malicious characters; with AOP, you can strip out those characters and additionally throw an exception/error anytime a dynamic SQL method is invoked. Perhaps more importantly, WAFs are almost useless at protecting against whole classes of vulnerabilities (e.g. missing server-side authorization on some critical functions) whereas AOP is extremely useful (e.g. transparently adding authorization checks to the actual business methods, independent of which interface they are called from). What’s amazing about AOP is that you can implement these changes without actually modifying the source code — one of the primary advantages of WAFs.
Is AOP always more appropriate than WAFs? Well, not quite. Similarly, WAF and AOP can protect applications when raw source files are unavailable. Both also require at least some application-level knowledge. However, AOP typically requires a deeper understanding than WAF. Without prior AOP experience, the off-chance of an implementation mistake is more likely to occurr with AOP than with a WAF.
WAFs are probably a better fit to protect those apps that are developed externally and/or for which you may not have the code/skillset to understand its internal workings. AOP is not an easy sell because it’s poorly understood by most of the IT community. Don’t expect the PCI data security standard to say “perform code reviews, use an application firewall, or implement security through aspect oriented programming” anytime soon. Another roadblock is that while AspectJ has been around for 11 years, few of the other aspect-oriented languages enjoy quite the same maturity and support.
All that being said, I’m sure Andre has made you aware of many of the shortcomings of WAFs (at least, compared to how they are being marketed). AOP is gaining traction in the developer community, as well as for security specific toolkits (check out Spring Security and see how they use AOP to implement method-level authorization). Later this year, we’ll be hosting an open source project on useful security AOP aspects at Security Compass. For the time being, make sure to at least consider AOP as an alternative when modifying existing source isn’t an option.

Personally I see WAFs as a concept that can be implemented in a number of ways. Network gateway, web server embedded, AOP–those are all different implementations of the same thing, and I don’t think we should be partial to any particular implementation: people should use whatever works for them. The network gateway WAF implementation is popular because it does not require anything to touch applications. There is the drawback of impedance mismatch–which you mention–that this increases the danger of different interpretation of the same data stream. AOP implementations have their own challenges, one being that each application needs to implement its own defence, and another that, in most cases, you need to build to entire functionality from scratch. To take this further, the concept of application self-defence is great, but we need to support it with toolkits (so that you don’t have to start from scratch every time) and tools to handle logging, alert management and blocking (on a scale larger than single application node).
By the way, in response to:
> With a WAF, you can protect against SQL
> injection by stripping out malicious
> characters; with AOP, you can strip out those
> characters and additionally throw an
> exception/error anytime a dynamic SQL method
> is invoked.
I think that transforming input data in any way is very dangerous and nearly impossible to get right. To do it properly you have to have complete knowledge of what the application is doing with the input. If you know this you are better off fixing the application itself. Either that, or you are desperate, in which it is all right because you have no choice.
Could you share the procedure for using AOP to secure a real application? How about WebGoat? How many of the OWASP Top Ten can you eliminate from an application with AOP? Is doing it with AOP faster and easier to maintain than just doing it in the code?
AOP just seems like such a cumbersome way of doing security. The root of the problem is that you can’t just mash in security calls according to some pattern. You actually have to think. You need a lot of context too.
For example, in your article, you apply a single regex to an input field to stop XSS. But every field needs a different regex! You can’t use the same rule for output encoding either - you need to encode for the location within the HTML. Even logging (the AOP poster child) needs a custom log message for whatever is happening in the code - particularly for security logging.
For almost every example I can think of (validation, encoding, access control, logging, encryption, concurrency, direct object references, etc…) it would be faster and better to just update the code. Try using something like ESAPI to refactor security into an application instead.
Ivan, it sounds like you and I really aren’t disagreeing on too many fronts. Certainly WAFs are more applicable than AOP in some cases, and AOP is not the ideal solution for everyone. Also, you are correct about changing the data - I probably should have said “reject the payload” instead of “strip out malicious characters”. The only reason I used that example is because I know many applications do strip out malicious character, which is their way of fixing the application itself (even when they know the application intimately). I don’t mean to imply that it’s an ideal solution.
I don’t think that AOP and WAF are different implementations of the same thing. A WAF is external to the application, whereas AOP is internal and that alone is a critical difference. The powerful pointcut syntax with mature AOP languages offer developers a degree of granulaity that’s just not possible outside of the application. I also disagree that you need to build the entire functionality from scratch. You do have to build security aspects once, but after they’re built it’s a simple process to reuse them in other applications with different pointcuts and small tweaks to the actual advice. The toolkits you’re talking about are just that, and we hope to have a few of these aspects up for general use on our website later this year.
As you correctly stated, and as mentioned in the article, AOP isn’t a good fit when you don’t understand the application’s internals.
Cheers,
Rohit
Jeff, I don’t pretend that AOP is a 10 minute solution to fixing your code. You’re absolutely right that it requires context and you certainly need to think. I would challenge anyone to find a way to really secure an application without having to think or understand context.
Of course you can re-factor code instead. The big difference is that that the existing code becomes tightly coupled to the security mechanisms. As soon as you enter authorization calls on your methods or you sanitize input within business logic, you begin to scatter code - and code scattering has been proven to lead to more defects (one such study can be found here: http://www1.cs.columbia.edu/~eaddy/publications/Identifying,%20Assigning,%20and%20Quantifying%20Crosscutting%20Concerns.slides.pdf).
Perhaps more important, each security aspect is centralized. Yes there will be different advice for different fields, but in most applications many of the fields can be categorized together and use the same advice (e.g. text in comment fields, addresses, etc.).
What about using AOP for OWASP Top 10? That’s a paper on it’s own, but let me talk about XSS. Output encoding is one of the most common defenses, and the OWASP Reform project (part of ESAPI if I remember correctly) is a great tool for this. If you can identify the objects that will be used in the presentation tier then you can use AOP to call Reform and encode them just before they are passed to the presentation tier. You could also do this with simple code changes, but the difference with AOP is that you are encapsulating that security concern away from the code. A developer who understands the code base and has a strong application security background could be assigned to develop these aspects.
Logging is properly not the best poster child for AOP because you are right that sometimes it is so context sensitive that it needs to be put within the method code. On the other hand, there are many cases in large applications where standardized logging is happening consistently across many different objects (e.g. “Entering method ..” for all methods within the service layer). Why not take out that standardized logging statement away from each individual object and modularize it? There will still be some logging left in the object, but the code will be less scattered.
ESAPI is a great set of tools. I think it is even better when (some parts of it) are applied with AOP to occur transparently from the rest of the code. I’d also point out that I don’t think AOP can be used for ALL application security concerns (e.g. you can’t use AOP to convert dynamic SQL to prepared statements - that has to be built in).
As for securing WebGoat, I think that is a fantastic idea and something I will implement when I get some free time.
So yes it may be faster to secure code directly, but there are certainly advantages to fixing much of the application without actually changing the code.