A Slightly Snarky Overview of Security for Apache Tomcat
Apache Tomcat crops up a lot, and frequently having been configured by someone without a lot of security background. I’ll spend a little bit of time looking at some of what you can do to improve security at a high level - I won’t be giving step by step instructions, just trying to provide a feel for what the security features can do.
For implementation details, you should take a look at the official documentation. Tomcat 7’s security documentation is at Tomcat Security Considerations. For the most part I’m using their documentation as a reference to put together this post, so there should be a pretty close correlation, although I’m focusing on Tomcat options directly rather than what you can do with the host OS. Additionally, I’ll be passing up the SSL configuration - that’s straightforward enough, and there’s plenty of other people who can tell you how SSL certificates should be handled.
All of these points are primarily focused to a production server - mileage for development and testing servers will vary.
All that being said, let’s start by looking at the security manager.
Tomcat Security Manager
The Tomcat security manager provides a “sandbox”, which prevents constrains what actions the code can take. It is based on the Java security manager, which was originally designed to limit the impact a malicious Java applet could do when loaded in a browser - but unlike the Java browser plugin, Tomcat is around to stay.
I’ll spend a bit more time on this than most sections, as the security manager tends to be rather underused, likely due to the fact it can be a pain to setup. I’ll also break down the pros and cons of enabling it - spoiler, I’m for enabling! You can find the implementation details to use it on it’s page in the Tomcat Documentation
Basically, what the security manager does, is define what Java can and cannot do. It limits Java’s access to functionality that would let it impact the host OS, along with other applications. For instance, in the standard permission sets, you’ll find java.io.FilePermission. Take that away, and suddenly you’ll find your program can’t write to files anymore - which if it shouldn’t be doing that in the first place, is a rather good thing!
One final thing to be clear on - to use the security manager effectively, you must have a change process before modifying the policy file. Otherwise, you’re likely to find it changes whenever it is convenient, which will likely end with it being almost as open as when it is turned off!
If at all possible you really should enable the security manager - even though there are more drawbacks than benefits listed here, the added security is a major benefit.
By enforcing permissions on what code can do, you limit the damage that maliciously inserted code can do, whether it has been inserted via a vulnerability in Tomcat, a malicious insider, or some other weakness (assuming that the policy file is better protected than the code).
As an added benefit, it provides a easy and very reliable source to help you define the attack surface of your application - if the permission for it isn’t provided for, the code isn’t doing it.
On an older project that hasn’t been using the security manager, trying to turn it on will likely result in the code being unable to run, and a significant amount of time and effort being expended to work out the appropriate permissions.
Additionally, on any project a certain amount of code and configuration discipline is required for the security manager to be of any use (which might be a benefit come to think of it). From a code perspective, programmers must understand and accept that they cannot simply start using a new feature that requires new permissions enabled. More significantly, the configuration of the security manager policy file must be maintained and protected against any unauthorized changes. If the security manager gets to be changed without review, just to make things more convenient, it won’t be long before every permission possible is opened up.
As a final potential drawback, the Tomcat documentation mentions that the security manager is not usually enabled on most servers - which means both that the community support for it is lower, and that there is a higher potential for bugs with it enabled.
Non-Management Default Applications
There are two types of default applications in Tomcat - management applications and everything else. First we’ll address the latter category - which consists of documentation and examples.
The short of it is - remove them. Keep these things on your development server, maybe even your testing server, but don’t let them make it as far as production. If your users needed documentation or examples on Tomcat, they shouldn’t be looking at the server hosting your web application. The only thing that these applications can contribute to your production server is an expanded attack surface or clues to an attacker what version of Tomcat you are running.
Default Management Applications
There are two management applications on Tomcat by default - the Manager and the Host Manager. The manager lets you perform everyday tasks, in particular deploying applications. The host manager allows you to configure and create virtual hosts.
My recommendation - surprise! - is to disable both of these as well. None of these are activities you want to make easy for anyone - both to prevent hackers from getting in, and to help enforce a change management policy.
If you really must leave these open, limit what IP addresses can access it (if possible just localhost), and ensure that all users with access to it are using very strong passwords. If necessary, look at hiding it away behind a reverse proxy. But really, on your production server, just disable it.
Configuration Options in server.xml
Going right down the list from the documentation (well, when it fits within the scope), quick points on what you should set things to and why.
- shutdown port - disable it, unless you have a really good reason to need to be able to remotely shutdown your production server. At a minimum, make sure that the Internet can’t reach this, and that there’s a very strong password on it.
- Listeners - have only what you need
- Connectors - different ways of connecting to the server, keep only what you need
- address - controls what IPs can connect. If you are running with a set of users limited to certain IPs, restrict to them to improve security
- allowTrace - enables the TRACE HTTP request. Try to keep this to your testing and development servers. If you must turn it on in production to fix an issue, turn it right back off afterwards.
- maxPostSize - limits how much a client can POST to prevent DoS attacks with large files. Keep it as low as works for your application.
- maxSavePostSize - limits the POST size from a client for certain types of long-running authentication. If you aren’t using this type of POST, set it to 0, otherwise as low as you can.
- maxParameterCount - limits the amount of parameters for GET and POST, for DoS protection.
- xpoweredBy - keep it turned off, so that you can reduce the amount of information about your Tomcat version going to potential attackers (though I’m sure you upgrade every time a new security fix comes out).
- server - value for the server HTTP header. As per usual, the less you tell an attacker, the less they know what to do to you - so set this accordingly.
- autoDeploy - setting to true provides you with the convenience of putting an archive file in a directory, and letting Tomcat deploy it for you without anymore effort on your part! Aside from potentially making an attacker’s life easier, this makes it much easier to have one of those “oops, just deployed testing to production” moments.
- deployOnStartup - rather than defining the application context manually, you can have it automatically deploy on startup. It might be less immediate, but this still can lead to the same unfortunate situation as autoDeploy can.
- deployXML - let’s Tomcat figure out an application’s permissions (and other things) from the context.xml file. This gets disabled if you use the security manager, you did turn that on, right?
- Context - the context in which an application runs
- crossContext - whether a context can get to resources from another context. Enable only with caution, and then only on trusted applications, since this allows one application to mess about with another.
- privileged - whether a context can use “container provided servlets like the Manager servlet”. You probably should never have a reason to be doing this, unless you are making something that is supposed to be managing Tomcat.
- allowLinking - whether a context can use linked files. Generally speaking, better to leave this off, so you can more clearly keep track of what the context has access to (i.e. the files physically in the folder, and nothing else).
- Valves - lets you log and match IPs to better track and control who has access to your application. At least look at logging remote addresses with an AccessLogValve.
I didn’t cover everything there is to cover about Tomcat security, but I tried to hit some of the high points, and more importantly, why they matter. In the end, you need to look at the documentation, and turn a critical eye to anything that is turned on that doesn’t have to be. And remember - even once the host (both Tomcat and everything else) are locked down, the application you develop still has to be concerned with security, or else all the hard work you did to secure Tomcat will be in vain.
One other point to mention, if slightly out of scope. You should consider using a reverse proxy between your Tomcat server and the Internet. By hiding away your server (or servers) you can limit the amount of information an attacker can find - potentially further reducing what an attacker can learn (even beyond what some of the configuration options do). Of course, just because you are using the reverse proxy doesn’t mean that you should leave default applications enabled, it just provides another line of defense - and defense in depth is what we all need.