Secure Your Spring Application Configuration With Jasypt

October 9, 2008

By and large, the applications that we deploy are configured at runtime by using the Spring PropertyPlaceholderConfigurer. For those of you not familiar with this concept, basically, any environment specific properties in our application or even properties that we just want to be able to easily change, are defined using Ant style property syntax within our Spring beans configuration.

For instance, our DataSource configuration looks something like this:

<bean id="dataSource" class="com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean"
          destroy-method="close">
      <property name="uniqueResourceName" value="My Primary Datasource"/>
      <property name="driverClassName" value="com.inet.tds.TdsDriver"/>
      <property name="url" value="jdbc:inetdae7a:${database.host}:${database.port}?database=${database.name}&amp;secureLevel=0"/>
      <property name="user" value="${database.user}"/>
      <property name="password" value="${database.password}"/>
      <property name="testQuery" value="select 1"/>
      <property name="maxPoolSize" value="50"/>
      <property name="minPoolSize" value="20"/>
      <!-- Setting reapTimeout=0 because atomikos incorrectly reaps nonxa connections. -->
      <property name="reapTimeout" value="0"></property>
    </bean>

By defining a PropertyPlaceholderConfigurer, we can have Spring inject the appropriate properties for this DataSource when the application starts up:

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <value>classpath:runtime-properties/${env}/my-application.properties</value>
        </property>
        <property name="nullValue">
            <value>null</value>
        </property>
        <!-- Force system properties to override any deployed runtime properties -->
        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
    </bean>

For instance, my file runtime-properties/dev/my-application.properties would contain:

database.host=localhost
database.user=myuser
database.password=mypassword
database.name=myapplicationdb
database.port=1433

When we deploy our application, we deploy ALL of the runtime property files for all of the different runtime environments. By injecting the env property into the container at runtime, we tell the application which runtime properties to use, e.g.:

-Denv=dev

This is usually done either in the startup script or the startup configuration for the container. For example, in JBoss, we would add this to the run.conf file or the run.sh script.

This approach opens up some security issues, however. Now, all of my database credentials for all of my runtime environments are packaged up in cleartext in my single WAR artifact. If, for instance, the sys admin who manages our deployments in our testing environments (integration and staging) is not the same sys admin that manages our deployments in our production environment, especially if this is security related (only trusted senior administrators can manage production applications), we have a security hole because the credentials for all environments are stored in the WAR.

Historically, there has been no easy way around this. Typically, one would generate a secret key that could be used to decrypt the passwords if they were encrypted in the application configuration but then if you put this secret key IN the application deployment, you STILL have a security hole–any sufficiently determined adversary can use this key to decrypt your encrypted passwords.

Recently, I stumbled across the Jasypt project. It aims to provide some simplified interfaces into the Java Encryption API’s. The feature it offered that most appealed to me, however, was the integration that it offers for Spring that dovetails nicely with my configuration.

Jasypt offers a special implementation of the PropertyPlaceholderConfigurer called the EncryptablePropertyPlaceholderConfigurer that allows you to encrypt some of your properties in your configuration files and have them decrypted on the fly when the application is starting. What’s more important, is it allows you to pass the encryption key, or ‘password’ into the application as a system property at runtime, decoupling the knowledge of the key from the deployable artifact.

Let’s see how this would work

First we would need to decide on an encryption algorithm and a password. Then we would use the commandline tools that ship with Jasypt to encrypt our database password above:
./encrypt.sh input="mypassword" algorithm=PBEWithMD5AndTripleDES password=jasypt_is_cool
Jasypt will output something that looks like:

----ENVIRONMENT-----------------

Runtime: Sun Microsystems Inc. Java HotSpot(TM) Server VM 10.0-b23

—-ARGUMENTS——————-

algorithm: PBEWithMD5AndTripleDES
input: mypassword
password: jasypt_is_cool

—-OUTPUT———————-

AUP/WSfdvbAfVuBJW/kbXsqh2qu8yWiJ

Then, we update our configuration file and replace:

database.password=mypassword

with:

database.password=ENC(AUP/WSfdvbAfVuBJW/kbXsqh2qu8yWiJ)

The syntax ENC(...) tells the EncryptablePropertyPlaceholderConfigurer that this property is encrypted.

Now, we will add the beans for the encryptor and it’s configuration:

    <bean id="jasyptConfiguration"
          class="org.jasypt.encryption.pbe.config.EnvironmentStringPBEConfig"
          p:algorithm="PBEWithMD5AndTripleDES"
          p:passwordSysPropertyName="jasypt.encryption.password"/>

    <bean id="propertyPasswordEncryptor"
          class="org.jasypt.encryption.pbe.StandardPBEStringEncryptor"
          p:config-ref="jasyptConfiguration"/>

The important thing to take away from the above is the configuration. The property passwordSysPropertyName tells Jasypt that it should load the encryption password from a system property named jasypt.encryption.password.

Now, as I described above, I add a runtime property to my container so that this password gets injected into the runtime environment as a system property:

-Djasypt.encryption.password=jasypt_is_cool

The final step is to change the PropertyPlaceholderConfigurer and wire it up to this encryptor:

    <bean class="org.jasypt.spring.properties.EncryptablePropertyPlaceholderConfigurer">
        <constructor-arg>
          <ref bean="propertyPasswordEncryptor"/>
        </constructor-arg>
        <property name="locations">
          <value>classpath:runtime-properties/${env}/my-application.properties</value>
        </property>
        <property name="nullValue">
          <value>null</value>
        </property>
        <!-- Force system properties to override any deployed runtime properties -->
        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
    </bean>

And that’s it! I’ve now added another layer of security to avoid having my production passwords floating around in my deployable artifact. It is generally a good idea to record this configuration in a secure location outside of source control that has limited access. This configuration should include the actual database password, the Jasypt encryption password used and the Jasypt algorithm that was used to generate the encrypted password, at a minimum.

Cheers!

About these ads

14 Responses to “Secure Your Spring Application Configuration With Jasypt”

  1. miluch Says:

    Hi

    Thanks for a great post. In my projects i do not have a problems with plain text passwords cause i usually acquire connections (DB connections, JMS connections) from JNDI of application server. In such environment admin is responsible for creation and configuration of connections and then binding them to JNDI.

    In a standalone applications (non-managed environments) the technique presented above is really cool. The one thing i do not like is that password is passed as plain text to startup script and i am quite sure if you do: ps -aux or use any tool that can hook to application server process you could see the password.
    Obviously you need to take a look in your codes and find the encrypted password and algorithm used to figure out DB password.
    I am not security guy and i do not know how to improve this process but i just perceive it as a slight security hole :)

  2. heuristicexception Says:

    Thanks for the comment.

    I would consider storing your passwords in JNDI as no MORE secure than the example I gave above since JNDI is not password protected so anyone who has network access to your JNDI provider can retrieve your passwords.

    As to the startup password comment..remember, at some point, the password (really, an encryption key) needs to be available to the application. It’s a chicken/egg problem…at some point, any security mechanism will always be vulnerable. That’s why security is applied in layers.

    Think about it this way, if I change the way I pass the password to the application (so you cannot sniff it with ps), it STILL needs to be on the system somewhere (perhaps in a property file). So, if someone has physical access to the server (e.g. key to the server room) they can still eventually get access to the security key through brute force means.

    To address your specific concern, one way to improve (but not completely eliminate) the security hole you perceive is to store the security key in a property file. With JBoss, you can then make these properties available at runtime using the -P flag (e.g. -P additional.properties); jboss will read the file and add these properties as system properties. That way the key can not be sniffed via something like ps. However, if you have shell access to the machine and the correct permissions, you’d still be able to access the properties file.

    Again, layers…. :-)

  3. miluch Says:

    Hi
    Thanks for an answer. I also see it as a key-egg problem.

    In my post i wrote about having DB pool bound to JNDI but not jdbc user/password.
    I do not have a lot of experience with different jee servers but on websphere you define JCA authentication data: username/password and then make your datasource reference these.

    I would have to check if these authentication data are bound to JNDI but i am quite sure not.

  4. dibyajyoti Says:

    Hi

    The above information is very usefule.thanks for the above post.

    Can you please share a demo source code for the above example that demonstrates integrating Jasypt with Spring Security .

  5. heuristicexception Says:

    I haven’t integrated Jasypt with Spring Security and don’t have any plans to at this point.

  6. Mike Says:

    How did you setup the runtime property?

  7. heuristicexception Says:

    We use a java service wrapper on our *nix application servers and there is a .conf file where the various runtime properties (e.g. java memory settings) are configured. We added it there.

  8. tim Says:

    I’m a bit confused about the purpose of this post. It’s probably an added security layer to container-managed application, where the key is stored as an environment variable at run time. the -D property will still have to be setup by sysadmin, which is no difference than Websphere’s JCA security – set up by a sysadmin. And that the application will refer to the data source by it’s JNDI name, so really…no reason why username/password should be in clear text in your Spring config in the first place. In this regard, Jasypt doesn’t really add any additional value to db connection security.

    You bring up clear text password problem for non-managed stand alone application, suggesting Jasypt can be the solution. Again, it boil down to where to store the encryption key. If passing in the key as an environment variable, such as -Djasypt.encryption.password=jasypt_is_cool , then clearly :ps can easily read this information. And btw, once the key is obtained, the ENC(…) loudly say that Jasypt is used, the encryption schemes is specified in the property file as well…

    So, i would say for stand-alone application, depending on how secure you want it, one should just hard-code the password, then obfuscate your byte-code. Of course, the price is rebuilding the app every time the password is changed.

  9. heuristicexception Says:

    A couple of things:

    1) We don’t use JNDI for our DS so there is no server bound config. Our application is portable, which means I can drop the same artifact (.WAR, .EAR) on ANY of our application servers in our test/integration environment as well as production and it will run.

    2) You are right, someone on the physical machine where our application is running can see the key if they do a ‘ps’. That’s why I explained that security is all about LAYERS. The people who have access to our production servers are not necessarilly the people who have access to our integration servers (or vice versa). Frankly, they don’t even need to do a ‘ps’ they can just look in the startup script for the jboss server to see the password. The point is, that personA who has admin rights to integration but not production can’t open the WAR and find out the password for the production database server to which they have no access.

    Again, security is about layers. This is just providing another layer. BTW, obfuscation won’t work in your case because Strings are not obfuscated by a bytecode obfuscator, just classnames, variable names, parameter names and method names. Think about the ramifications if your CL input prompt “Hi, enter some data:” was obfuscated….

  10. Dzenno Says:

    To this last post, I actually implemented Jasypt property encryption for my configuration. However, the bank that took the project didn’t want any clear text passwords/jasypt keywords anywhere. So my web app that typically up to this point was loading all spring config files using the typical context listener and applicationContext.xmls from the classpath now had to follow a 2 step startup since keyword “could not” be specified as a runtime parameter and Spring + WebPBEConfig don’t play nice (servlet context starts spring AND WebPBEConfig servlet/filter) and on startup of my spring beans, they require decrypted config properties (database datasource tries to connect). It took about 2 days to get it right but now it finally works. Took a while until I figured how to accomplish this in an already large, built-out web app.


  11. [# Encriptación con Jasypt en Java ]…

    Hoy les voy a hablar de Jasypt (Java Simplified Encryption), es una librería Java que nos permite realizar cifrados con una facilidad extraordinaria sin necesidad de adquirir conocimientos de criptogafía. Algunas de sus características son: Sigue los ….

  12. Jack Says:

    I tried above code. i am getting belwo error.
    JZ002: Password property ” too long. Maximum length is 30.


  13. Nice article, it was very useful. Thanks.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: