Spring e datasource: come criptare la password del database

Eccoci al terzo e ultimo episodio della saga sulla sicurezza della vostra password del database. In due post precedenti abbiamo visto come cifrare la password del datasource in JBoss AS 7 e in Tomcat. Se però non lavorate né con JBoss né con Tomcat, usate Spring e preferite far gestire il datasource a lui e rimanere più generici possibili, ecco come criptare la password con il semplice aiuto di un framework esterno, ovvero Jasypt!

Encryption for dummies

Il problema della sicurezza e degli algoritmi di criptaggio è un mondo che conosco poco, ma se quello che ti interessa è avere un certo livello di sicurezza nella cifratura della tua password senza sbatterti troppo, questo è il framework che fa per te! (E per me!) Soprattutto perché nativamente si integra con Spring. Per includerlo nel vostro progetto basta inserire nel pom:

<dependency>
   <groupId>org.jasypt</groupId>
   <artifactId>jasypt-spring31</artifactId>
   <version>1.9.2</version>
</dependency>

Partiamo però dall’inizio.

C’era una volta un datasource…

Nei progetti Spring che gestiscono il datasource (invece che chiederlo in JNDI al server), la sua dichiarazione è qualcosa del tipo:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
   <property name="driverClassName" value="${db.driver}" />
   <property name="url" value="${db.url}" />
   <property name="username" value="${db.username}" />
   <property name="password" value="${db.password}" />
   <property name="initialSize" value="${db.initialSize}" />
   <property name="maxActive" value="${db.maxActive}" />
</bean>

dove i parametri vengono letti da un semplice file di properties (chiave/valore) con:

<util:properties location="classpath:db.properties"/>

db.username=test
db.password=test
db.driver=com.mysql.jdbc.Driver
db.url=jdbc:mysql://localhost:3306/test
db.dialect=org.hibernate.dialect.MySQL5Dialect
db.initialSize=10
db.maxActive=50

Fin qui niente di nuovo. Occhio alla classe del datasource: come suggerisce il javadoc di Spring, è buona norma usare un connection pool e non il datasource fornito da Spring stesso in un ambiente di produzione.

Jasypt in azione!

Jasypt mette a disposizione un namespace specifico per Spring in modo da configurare l’algoritmo di cifratura che useremo e su quali file di properties verrà applicato. Per chi lo preferisce, può usare la dichiarazione esplicita dei bean coinvolti nella configurazione e mascherati dai tag di Jasypt.

Ci basta quindi sostituire util:properties con:

<enc:encryptor-config id="encConf" password="my-supa-dupa-passphrase" algorithm="PBEWithSHA1AndDESede"/>
<enc:string-encryptor id="stringEnc" config-bean="encConf"/> 
<enc:encryptable-property-placeholder encryptor="stringEnc" location="classpath:db.properties"/>

  1. encryptor-config: dichiara un bean encryptor di configurazione dove scelgo l’algoritmo di cifratura e una parola chiave usata nella codifica (lo stesso che abbiamo usato nel post dedicato a Tomcat).
  2. string-encryptor: applica la configurazione ad un encryptor di stringhe;
  3. encryptable-property-placeholder: carica il file di properties e tenta di decifrare le voci criptate. Come fa a riconoscerle? Le voci codificate sono dichiarate così:
    db.password=ENC(vz8Xp5eOh2jIb8RZi6IDUg==)
    

Semplice no? Tre righe di xml e la password è protetta! Ma da dove è uscita? Possiamo calcolarcela in modo piuttosto semplice.

Creiamo la nostra password cifrata

Purtroppo, a differenza di come abbiamo visto con JBoss, dobbiamo farci un nostro main per criptare la password da sostituire nel file di properties.

Per essere sicuri di usare lo stesso encryptor che Jasypt userà per la decodifica, creiamo un semplice bean e glielo iniettiamo:

<bean class="it.cosenonjaviste.services.utils.EncryptionUtils">
   <property name="encryptor" ref="stringEnc"></property>
</bean>

Scriviamo quindi un semplice main che carica il contesto Spring e codifica la password passata come argomento:

public class EncryptionUtils {

   private StandardPBEStringEncryptor encryptor;

   public String encrypt(String plain) {
      return encryptor.encrypt(plain);
   }

   public static void main(String[] args) {
      try (ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
            "classpath:db.xml");) {
         EncryptionUtils encryptionUtils = context.getBean(EncryptionUtils.class);
         System.out.println(encryptionUtils.encrypt(args[0]));
      }
   }

   public void setEncryptor(StandardPBEStringEncryptor encryptor) {
      this.encryptor = encryptor;
   }
}

Abbiamo quindi pronta la password da sostituire nel nostro file di properties!! Questo esempio è stato testato con Spring >= 3.1. Per le versioni precedenti dal sito di Jasypt è possibile trovare le soluzioni più adatte alla vostra versione.

Un piccolo approfondimento

Come nel post dedicato alla cifratura della password per JBoss, anche in questo caso non abbiamo fatto altro che spostare il problema. Riprendiamo la configurazione dell’algoritmo:

<enc:encryptor-config id="encConf" password="my-supa-dupa-passphrase" algorithm="PBEWithSHA1AndDESede"/>

Per un utente esperto, conoscere l’algoritmo e la sua password di cifratura, è un attimo risalire alla password del database. Fortunatamente Jasypt offre altri due modi per passare la password di cifratura. Possiamo infatti sostituire l’attributo password con:

  • password-env-name: possiamo far riferimento ad una variabile d’ambiente nella quale registreremo la password. Una volta avviato il sistema può essere tolta senza problemi.
  • password-sys-property-name: possiamo passare la password come parametro della JVM, in modo da non averla scritta fisicamente nella configurazione del nostro applicativo.

Lo stesso tipo di sicurezza può essere applicato anche all’attributo algorithm in modo da non essere dichiarato esplicitamente nella configurazione.
Dovendo scegliere, preferirei la prima di queste due soluzioni perché non lascia traccia nel sistema della password dell’algoritmo di cifratura.

Andrea Como

Sono un software engineer focalizzato nella progettazione e sviluppo di applicazioni web in Java. Presso OmniaGroup ricopro il ruolo di Tech Leader sulle tecnologie legate alla piattaforma Java EE 5 (come WebSphere 7.0, EJB3, JPA 1 (EclipseLink), JSF 1.2 (Mojarra) e RichFaces 3) e Java EE 6 con JBoss AS 7, in particolare di CDI, JAX-RS, nonché di EJB 3.1, JPA2, JSF2 e RichFaces 4. Al momento mi occupo di ECM, in particolar modo sulla customizzazione di Alfresco 4 e sulla sua installazione con tecnologie da devops come Vagrant e Chef. In passato ho lavorato con la piattaforma alternativa alla enterprise per lo sviluppo web: Java SE 6, Tomcat 6, Hibernate 3 e Spring 2.5. Nei ritagli di tempo sviluppo siti web in PHP e ASP. Per maggiori informazioni consulta il mio curriculum pubblico. Follow me on Twitter - LinkedIn profile - Google+