Presented by Mark Thomas, committer on Tomcat for five years
There have generally been few Tomcat threats in the wild (at least that have been
reported). One in July 2008 was reported that was hackers installing a webapp, always
* for something - anything). It allowed hackers to get access to a
shell on your server. If you were running as root, game over. The way this was being
installed was through deployed servers with a Tomcat admin that had not been secured
(blank or default passwords). This is obviously a very poor idea.
How can you protect yourself against Tomcat security attacks? Read more to find out.
The first rule of thumb is to make sure you have taken your standard precautions, such as OS hardening, firewalls, etc. Next, uninstall all of the default Tomcat applications, which are much better used in development environments (docs / examples / host-manager / manager / default ROOT application). You can run Tomcat in a security manager, but this is not a well tested method - you will need to completely test your application before deploying with it.
Tomcat is reasonably secure by default. One of the first things you can do is get rid of
most of server.xml, including comments, to make it easier to read, etc. Using
<Server ... /> tag. The shutdown port should obviously use a strong password
(long, and random). Another tip, not necessarily related to security, but to availability
is that the
<Listener ... /> tag is not well supported natively on Solaris.
Note on the following points - there was a lot to cover, and he was moving through it quickly. These notes are a bit sparse, but are his recommended best practices. He said to email the users list if you have further questions.
<Connector .. />
- Do you need HTTP and AJP enabled?
address="..."(defaults to all) - can you lock this down to a single IP? i.e. your proxy?
allowTrace="false"- you should leave this off
server="Server: Apache-Coyote/1.1"- you can change these to try “security by obscurity” by confusing hackers as to what server you are actually running.
AJP specific configuration:
request.secret="..."should be strong if used / although AJP connections are not encrypted, so this secret will be in plain text between the two servers - so not necessarily all that useful
tomcatAuthentication="true"(default) - if you want httpd (for example) to do your authentication, you can set this to “false”, and configure mod_jk appropriately so that your front-end proxy can handle authentication and pass the username back to Tomcat
<Host ... />
autoDeploy="false"- should change it to false (defaults true)
deployOnStartup="true"- if you change this and autoDeploy to false, the only apps deployed will be those defined in server.xml - which can block accidental (or malicious) app deployment
<Context ... />
crossContextshould normally be false
allowLinking- should not be changed on case-insensitive operating systems
<Valve ... />
- Always configure an access log valve so that you can confirm when things happened and debug issues
- Remove / archive old log files
- Typically, do one per host
- Use a remote address filter where possible
- Using allow for this is better than deny - only allow known addresses that should be
able to access the application (don’t forget to escape the periods in the IP address
- this attribute is a regex - use .)
<Realm ... />
- Don’t use memory or UserDatabase or JDBC realm in production. The first two require Tomcat restart, and the JDBC only uses a single JDBC connection.
- You can use DataSource realm.
- JNDI realm also uses a single connection
- JAAS realm is not wisely used, and commonly has unreported bugs. They do support it, but because it’s not widely used, there can be untested issues that arise.
- There is no account lock-out implemented - which allows brute-force attacks to work after some time. They are trying to get a fix for this into 6.0.19
- New in 6.0.19 should be LockOut realm - it wraps around standard realms and provides a lock-out mechanism for multiple failed attempts for the same user. With this, there will also be the ability to have multiple realms for authentication - if any match, you get access - so you could use, for example, a tomcat users file for admins and a JNDI realm for users.
<Manager ... />
entropy="this.toString()"can be deterministic, so you can use APR or
randomClass="java.util.Random"to define a true random entropy provider
org.apache.catalina.connector.RECYCLE_FACADES="false"- I didn’t catch all of the details on this, but he said the docs are right - look at them, even though they sound counter-intuitive
org.apache.catalina.CoyoteAdapter.ALLOW_BACKSLASH="false"- recommended setting
org.apache.tomcat.util.buf.Udecoder.ALLOW_ENCODED_SLASH="false"- recommended setting
org.apache.coyote.USE_CUSTOM_STATUS_MSG_IN_HEADER="false"- recommended setting - if you turn it on, make sure that everything put into your sendError calls is in ASCII - don’t allow user data to be put into sendError calls
- Consider locking your database down to where the username that your web app uses to access the DB is only valid when it comes from the IP of your Tomcat server.
- in the default servlet, you should use
-listings="false". For one thing, directory listings are not that secure of an idea, and they are very slow on Tomcat. If you absolutely need them, there is a patch that speeds them up - you’ll need to research and apply yourself.
- He says “the invoker servlet is horrible, evil - don’t even use it, ever”.
- Most monitoring tools also provide management functionality, which introduces risk that you’ll need to really think about. LambdaProbe is a good monitoring app, but weirdly disappeared from the net a couple months ago. He says to email the users list and someone there will provide it for you.
- Hash out what you will do in the even of an attack ahead of time - don’t waste the time after you were attacked.
- Using a cluster obviously reduces downtime - load balance it with httpd or similar.
- Easing upgrades - you can separate your configuration files from your binary tomcat
files by using
CATALINA_BASE=/your/instance/config/path, and then start and stop which binary dist you want to use.