Last updated at Thu, 05 Nov 2020 18:08:28 GMT


For the final installment in our history of web security, it's time to bring the story in to the present. The problem with bronze-age techniques, aka the stateful waf, is that they put a security engine in front of your application that needs to build a model of what the application does. Your ability to build effective security is directly related to the accuracy of the application model. As long as the model accurately predicts the application's behavior, everything will be good.

The reason why second-generation WAFs are hard to manage is that it's basically impossible to build a front-end that accurately predicts how the application works. As the old saying goes, “The difference between theory and practice is greater in practice than in theory.” Conceptually, it's very easy to build a model of the application and prevent “bad stuff” from reaching the app. In practice, a second generation of WAF is incredibly noisy and requires an immense amount of attention to just get the basic job done.

If the core challenge presented by a second-gen WAF is managing its constant chatter, there are a two ways of dealing with it. The main incremental improvement was automation and analytics to algorithmically screen out false positives. Security software still generates a flood of alerts, but it's good at “pre-ignoring” irrelevant alerts so you don't have to.

As is usually the case in technology, sometimes you need to make more than an incremental improvement. Rather than post-process alerts to make sure they're important, an alternative is to build security into the application run time. By doing so, the application is modeled by … the application itself. Well, technically, you're no longer building a model. You're now looking at what the application will do, with the opportunity to intervene when necessary. Rather than try to predict that a request calls a database, opens a file, or starts a shell to execute a command because the request is likely to trigger those actions, watching the app runtime tells you that the application actually performed those actions.

There are a few key benefits to integrating security into the application with this method. Alerts are much more accurate: alerts are much more likely to be true positives because you're seeing what the application is actually doing rather than making a (hopefully educated) guess. With security integrated into the app, the modeling problem goes away. There's no learning mode, and new features or changes in behavior are reflected immediately. When the app changes, there's no need to update the model of the application that you have sitting in front of the app for security. You want to deploy several times a day because that's what cool apps do? No problem!

Plugging into the app runtime also has important operational benefits. The security layer is part of the app, so when you need more app capacity, your scaling framework brings up more app capacity, as well as just the right amount of security to go along with it.

The main drawback to working with the application runtime is that you have to have a way of getting access to it. Java agents are part of the language, and let you monitor the Java runtime. (Here's a good presentation on how they work.) In a security product, we use Java agents to watch code loading, which helps us build a dependency tree to look at the packages the app uses, and then watch important areas of functionality like database and shell command execution. JavaScript, Ruby, and Python work a little bit differently, and allow us to instrument individual function invocations, but the result is very similar.

The end of the series, but not the end of the story

So there you have it: a history of web application protection in four parts: a technology that began with a stateless (and brainless) pattern matcher, grew to include a model of the application, and finally became deeply integrated into the application. The intersection of agile development methods, continuous integration and deployment, and the flexibility of cloud execution has driven application security harder than ever before. Protecting the application at runtime enables a whole new frontier of application security. Instead of trying to keep up with development velocity, security teams can monitor for the signs of successful breach, rather than the flood of attacks that target old vulnerabilities that your application may not have (or may have patched).