I’ve already written a bit about frameworks, both about using others’ and about building your own. This post will look at using existing frameworks a bit more, specifically around interesting security features.
Most of the discussion in the security area as it relates to frameworks is about CVEs (Common Vulnerabilities and Exposures). That’s reasonable, since there is a readily available pool of data and it’s possible to build a point solution to address the issue with relative ease. This is evidenced by some great open source tools (such as OWASP Dependency Check and Retire.js) as well as several commercial tools.
However, there are many other issues with frameworks outside of CVEs. I’d like to look at one of those issues in this post and consider how it might affect your security posture, as well as what can be done to address it.
Frameworks vary in shape and size, but generally, they all represent the ideal of reusable code. If some code is going to be written more than once, we should generalize it and work from a common code base so everyone will benefit. This has huge obvious advantages for development, but also for security. It’s one place to focus our efforts, and one set of code to review and analyze.
However, having one codebase to analyze doesn’t mean it happens (many eyes shallow bugs anyone ???). I pulled some numbers from here about several popular frameworks and posted their estimated lines of code below.
Hibernate (1.1 MLOC)
Spring Core (1.25 MLOC)
Log4J (80 KLOC)
Lucene (500 KLOC)
Commons IO (30 KLOC)
Commons Lang (70 KLOC)
Struts2 (830 KLOC)
Spring Boot (130 KLOC)
It’s a safe bet that many Java projects are relying on millions of lines of code in their deployed application, not to mention the container/server and operating system they are running on!
So, we know frameworks have significant benefits from the development perspective, and we know they can have known vulnerabilities in them (CVEs), but what about other security issues?
The particular topic I want to look at is frameworks that have some sort of “magic”. There is lots of functionality that could be classified as “magic”. One common example is auto-binding of web forms, ie. mapping request parameters to a backing object of some type. This has bitten many frameworks repeatedly, but the functionality is desirable, so people keep building it. Another example might be dynamic finder methods in ActiveRecord. No matter what the magic is, it can usually be recognized by the response people give when they learn about it – usually some variant of surprise + (excitement | horror) depending on the person.
A Few Examples
I’d like to consider a few examples (of which there are many) that I would call “magic” in popular frameworks.
Struts2 offers a plugin architecture that allows any JAR bundled inside a WAR to have a special configuration file (struts-plugin.xml), and the framework will auto-discover and enable it. That means that a JAR can now self-configure and has access to the same capabilities related to struts2 that the hosting application does. This is an interesting feature that allows for modularity, but very likely will catch both developers and security folks off-guard the first time they hear about it.
Note that the framework is pretty generous and gives plugins many extension points to override, including the ability to take over the core object creation functionality. This obviously produces many security concerns.
Servlet Web Fragments
In the servlet 3.0 spec, a new capability was introduced: web fragments. (similar to the struts2 convention plugin) This spec essentially allows any JAR bundled inside a WAR to have a special file (web fragment) that semantically gets copy-pasted into the web.xml. That means that a JAR can now self-configure and expose endpoints. (note: similar functionality is available via annotations) This is a significant change for many developers. By simply upgrading to the latest spec, I now have this significant new functionality. Also, this functionality is not necessarily heavily advertised. An example is below
welcome com.mysite.WelcomeServlet ... welcome /Welcome
Part of the significance with this issue is that it doesn’t matter really what frameworks you’re using. If you are deploying WAR files, this could affect you.
Spring Boot Actuator
The last example I want to cover is in Spring Boot. Spring Boot is a framework that is “opinionated”. It tries to provide some useful defaults that are helpful to get you going, then allow you to customize as needed. The framework emphasizes rapid development.
One of the very nice features it provides is the “actuator”. This is a feature that brings in the great metrics project, and sends data from the framework itself into the metrics by default. This is a fantastic feature if you’re in an environment such as micro-services (one of the primary targets for spring boot) because there is rich machine-accessible data to drive automated decision making and reporting.
Note that this portion of the framework is off by default. However, many of the examples online, both in the official documentation and many other tutorials, configure the actuator for use. One reason many people may not be aware of the tool is that the only thing required to enable it is to pull in a dependency. Add a maven or gradle dependency and spring boot auto-configures it.
The framework provides a startling amount of information by default. One of the standard spring applications (http://start.spring.io) is built with Boot, and exposes these endpoints to the world. Below I’ve listed most of the different endpoints along with some of the information they contain. It’s a significant amount of information. Consider this information being exposed in your own application.
– http://start.spring.io/trace – essentially the web server log with information about all clients connected (IPs/countries, etc.), cookies (may be useful for session stealing), referers, etc.
– http://start.spring.io/mappings – accessible urls – bad if you have any urls you don’t want exposed.
– http://start.spring.io/metrics – OS data – actually see the effect of DOS attempts as you go
– http://start.spring.io/info – dependency versions – helpful for checking against CVE’s
– http://start.spring.io/env – tons of data, OS, filesystem – versions of installed software, more dependency info, info about the environment (cloud space id, instance running port, etc.)
– http://start.spring.io/autoconfig – what’s autoconfiged and why/why not
– http://start.spring.io/configprops – multipart file sizes, jmx info
– http://start.spring.io/beans – classes that are loaded
– http://start.spring.io/dump – thread dump
Important note: if you also add spring security, many of the exposed endpoints are automatically protected by spring security. However, not all spring boot projects will use spring security and this protection does not apply to other security frameworks.
What Can You Do?
Many frameworks have some amount of “magic”. Above I’ve listed a few examples I find interesting, but there are countless more. So, what should you do with this information? Here are a few concrete steps you can take:
1. Know frameworks – Understanding the features provided by the framework (both well-known and hidden) is an important pre-requisite to using a framework. Using something you don’t understand almost always ends badly.
2. Assess frameworks – evaluate frameworks from a security perspective. This could be done with both manual and automated review techniques. This could be done as a private organization or in an open community. No matter the specifics, evaluating the framework is important. This is really a subpoint to knowing frameworks, but it is security specific.
3. Manage frameworks – as an organization, use only “approved” 3rd party libraries and only specific versions of those libraries. This step depends on 1 and 2. There is a wide range of technological solutions to this problem, but the idea is to ensure you know what you’re using and that you’ve decided (through a review of some defined acceptable level of rigor) that what you’re using provides an acceptable level of safety.
Frameworks provide lots of functionality. It’s our job as secure software implementors to understand the tools we’re using and their safety properties so that we can use them properly and provide secure applications.