2010-11-16 6 views
11

esiste un modo per nascondere/crittografare la password nel file di configurazione xml spring? Ho letto che è possibile con una sottoclasse "personalizzata" di DataSource, ma le soluzioni mantengono la chiave nello stesso file di configurazione come testo semplice ... quindi è un po 'inutile.Nascondi password origine dati nel file xml di primavera

C'è un modo per utilizzare KeyStore per questo? Ad esempio, leggere il valore da un keystore.

Grazie a tutti.

risposta

10

Sì, puoi farlo. Dovrai creare un bean wrapper attorno alla classe dell'origine dati. Ecco un esempio di come l'ho fatto prima. Spero che questo ti aiuti!

<beans> 
    <bean id="someDao" class="com.dao.SomeDAOImpl"> 
     <property name="datasource"> 
      <ref local="secureDataSource"/> 
     </property> 
    </bean> 
    <bean id="secureDataSource" class="com.ds.SecureDataSource"> 
     <property name="driverClassName"> 
      <value><your driver></value> 
     </property> 
     <property name="url"> 
      <value><your url></value> 
     </property> 
     <property name="username"> 
      <value><your user id></value> 
     </property> 
     <property name="password"> 
      <value><encrypted_pwd></value> 
     </property> 
    </bean> 
</beans> 

Quindi all'interno della classe SecureDataSource è necessario decodificare la password.

+0

Questo sarebbe più flessibile se si utilizzasse il modello decoratore (ad es. la tua origine dati contiene un'altra origine dati e inoltra tutto tranne la password) –

+0

Touche SP! Questo è stato veloce per dimostrare che si può fare. Ma l'OP può ridisegnarlo come vuole. – CoolBeans

+0

grazie bel consiglio! – blow

11

Qual è lo scopo di nascondere la password? Vi suggerisco di configurare l'origine dati nel contenitore (Tomcat, JBoss o qualsiasi altra cosa si usa) e iniettare l'origine dati nella vostra applicazione utilizzando JNDI:

<jee:jndi-lookup id="thedatasource" 
        jndi-name="java:comp/env/jdbc/thedatasource" 
        lookup-on-startup="false" 
        expected-type="javax.sql.DataSource"/> 

questo modo si dispone di non esporre e password nella vostra applicazione, ma solo in il contenitore della servlet.

+2

Sto sviluppando un'applicazione client-server desktop e voglio proteggere il DB dell'applicazione. Voglio essere unico in grado di toccare il mio db. – blow

+0

Corretto, per le app in blocco dovrai adottare un approccio diverso. – CoolBeans

+0

@blow che è praticamente impossibile, vedere la mia risposta aggiornata –

2

Buone opzioni sono state date, un'altra risposta ovvia è quella di utilizzare il PropertyPlaceholderConfigurer:

<context:property-placeholder 
    system-properties-mode="OVERRIDE" 
    location="classpath:database.properties" /> 

<bean id="dataSource" class="com.whatever.datasource.you.Use"> 
    <property name="password" value="${database.password}" /> 
</bean> 

Ora è possibile mantenere la password sia come una proprietà in un file di proprietà (che si potrebbe creare durante la distribuzione se non si desidera averlo in SCM) o come una proprietà di sistema (che si spera anche non sia raggiungibile da altri sviluppatori).

Chiarimento:creare durante la distribuzione è un po 'vago. Immagino che dovrai scrivere un programma di installazione che generi dinamicamente il file delle proprietà sul computer dell'utente finale, probabilmente abbinato a un meccanismo di registrazione/accesso.


EDIT: non ho ancora capito chi si nasconde le informazioni. Due teorie:

a) Le persone che hanno accesso al codice sorgente di
b) i vostri clienti

Se si tratta di una), poi vanno a modo mio. Tutti gli altri modi possono essere facilmente violati dall'altro sviluppatore, avviando l'applicazione con un debugger (e improvvisamente si trova all'interno dell'oggetto datasource e vede la password).

Se è b), quindi non hai possibilità, in pratica. Il cliente ha un sacco di possibilità per ottenere la tua password: debugger, agenti, manipolazione di bytecode, tessitura del tempo di caricamento ecc. Anche se non lo fa, dovrà solo collegare uno sniffer di porta per ottenere la password in chiaro testo. L'unica cosa sicura da fare è avere un nome utente/password per cliente (non memorizzare mai una password globale sulla macchina del cliente).

+0

@ S.P.Floyd - seanizer: penso di non capire questo. In questo modo, la password è memorizzata in database.properties, quindi chiunque può leggerlo, non è vero? – blow

+0

non se database.properties è ad es. creato dinamicamente durante la distribuzione. –

+0

Cosa intendi esattamente con "distribuzione"? La distribuzione è quando rilascio il mio software all'utente, vuoi dire questo? – blow

0

Ho avuto la stessa domanda di recente. Volevo memorizzare una versione hash della password in un file .properties. Ho fatto il trucco grazie alle opzioni precedenti: ho esteso lo DelegatingDataSource e ho annullato i metodi getConnection([...]).

public class UnhashingDataSource extends DelegatingDataSource { 

    private static final Logger LOGGER = Logger.getLogger(UnhashingDataSource.class); 
    private static final int HEX_RADIX = 16; 
    private static final String DB_PASS = "a_sample_password"; 

    @Override 
    public Connection getConnection() throws SQLException { 
     DriverManagerDataSource dataSource = (DriverManagerDataSource) getTargetDataSource(); 
     return getConnection(dataSource.getUsername(), dataSource.getPassword()); 
    } 

    @Override 
    public Connection getConnection(String username, String password) throws SQLException { 
     try { 
      DataSource datasource = getTargetDataSource(); 
      if (datasource == null) { 
       throw new RuntimeException("targetDataSource is null"); 
      } 
      MessageDigest md = MessageDigest.getInstance("SHA-1"); 
      md.reset(); 
      md.update(DB_PASS.getBytes()); 
      if (password.equals(getHexString(md.digest()))) { 
       return datasource.getConnection(username, DB_PASS); 
      } else { 
       throw new RuntimeException("Unable to connect to DB"); 
      } 
     } catch (NoSuchAlgorithmException e) { 
      LOGGER.error("Unknown algorithm"); 
     } 
     return null; 
    } 

    private String getHexString(final byte[] messageDigest) { 
     BigInteger bigInt = new BigInteger(1, messageDigest); 
     return bigInt.toString(HEX_RADIX); 
    } 
} 

Poi, ecco come l'ho usato nel mio applicationContext.xml:

# Using the unhashing datasource 
<bean id="entityManagerFactory" 
    class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
    <property name="dataSource" ref="unhashingDataSource" /> 
    # ... 
</bean> 
<bean id="hashedDataSource" 
    class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
    <property name="driverClassName" value="${datasource.driverClassName}" /> 
    <property name="url" value="${datasource.url}" /> 
    <property name="username" value="${datasource.username}" /> 
    <property name="password" value="${datasource.hash}" /> 
</bean> 
<bean id="unhashingDataSource" 
    class="my.package.UnhashingDataSource"> 
    <property name="targetDataSource" ref="hashedDataSource" /> 
</bean> 

Dove datasource.hash è una struttura (da un file .properties) memorizzato come:

datasource.hash = 2e54b0667ef542e3398c55a08a4e04e69b9769e8 

La pianura la password è ancora in bytecode ma non più direttamente in un file .properties.

0

Grazie per tutti i tuoi post e domande.

Speranza per i visitatori è chiaro il modo tecnico per crittografare la password leggendo questa pagina. Una cosa importante che vorrei aggiungere qui, se hai a che fare con la produzione, ti suggerirà sicuramente di usare qualsiasi "Algoritmo di hash sicuro" come SHA-256 con sale. È possibile considerare un algoritmo hash sicuro che utilizza salt come standard del settore.