2010-11-16 8 views
11

gibt es eine Möglichkeit, Passwort in Xml Spring Config-Datei zu verstecken/zu verschlüsseln? Ich lese das ist mit einer "benutzerdefinierten" Unterklasse von DataSource möglich, aber die Lösungen behalten Schlüssel in der gleichen Konfigurationsdatei als einfacher Text ... so ist ein bisschen nutzlos.Hide Datenquelle Passwort im Frühjahr Xml-Datei

Es gibt eine Möglichkeit, KeyStore dafür zu verwenden? Lesen Sie beispielsweise den Wert aus einem Schlüsselspeicher.

Vielen Dank.

Antwort

10

Ja, das können Sie tun. Sie müssen eine Wrapper-Bean um die Datenquellenklasse erstellen. Hier ist ein Beispiel, wie ich es vorher gemacht habe. Hoffe das hilft!

<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> 

Dann müssen Sie innerhalb der SecureDataSource-Klasse das Passwort entschlüsseln.

+0

Dies wäre flexibler, wenn Sie das Dekoratormuster (z. B. Ihre Datenquelle enthält eine andere Datenquelle und leitet alles außer dem Passwort weiter) –

+0

Touche SP! Das war eine schnelle, um zu zeigen, dass es gemacht werden kann. Aber das OP kann es so umgestalten, wie er es will. – CoolBeans

+0

danke schönen Tipp! – blow

11

Wozu dient das Verstecken des Passworts? Ich schlage vor, Sie die Datenquelle in dem Container (Tomcat, JBoss oder was auch immer Sie verwenden) konfigurieren und injizieren die Datenquelle in Ihre Anwendung mit jndi:

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

diese Weise können Sie nicht in Ihrer Anwendung zu belichten und ein Passwort haben, aber nur in der Servlet-Container.

+2

Ich entwickle eine Desktop-Client-Server-Anwendung, und ich möchte Anwendungs-DB schützen. Ich möchte einzigartig sein, das meine DB berühren kann. – blow

+0

Richtig, für Batch-Anwendungen müssen Sie einen anderen Ansatz wählen. – CoolBeans

+0

@blow das ist ziemlich unmöglich, siehe meine aktualisierte Antwort –

2

Gute Möglichkeiten gegeben haben, eine andere offensichtliche Antwort ist, die verwenden 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> 

Jetzt können Sie Ihr Passwort in einem Eigenschaften entweder als Eigenschaft halten Datei (die Sie bei der Bereitstellung erstellen können wenn Sie es nicht im SCM haben wollen) oder als eine Systemeigenschaft (die hoffentlich auch für andere Entwickler unerreichbar ist).

Klarstellung:während des Einsatzes erstellen ist etwas vage. Ich denke, Sie müssen ein Installationsprogramm schreiben, das die Eigenschaftendatei dynamisch auf dem Computer des Endbenutzers generiert, wahrscheinlich gekoppelt mit einem Anmelde-/Anmeldeverfahren.


EDIT: Ich habe noch nicht herausgefunden, wer Sie die Informationen aus verbergen. Zwei Theorien:

a) Personen, die Zugriff auf den Quellcode haben
b) Ihre Kunden

Wenn es a) ist, dann meinen Weg gehen. Alle anderen Möglichkeiten können leicht durch den anderen Entwickler verletzt werden, indem Sie einfach Ihre Anwendung mit einem Debugger starten (und plötzlich befindet er sich im Datenquellenobjekt und sieht das Passwort).

Wenn es b) ist, dann haben Sie grundsätzlich keine Chance. Der Kunde hat jede Menge Möglichkeiten, um sein Passwort zu bekommen: Debugger, Agenten, Bytecode-Manipulation, Loadtime-Weben usw. Auch wenn er nichts davon tut, muss er nur einen Port-Sniffer anhängen, um das Passwort klar zu bekommen Text. Die einzige sichere Sache ist, einen Benutzernamen/ein Passwort pro Kunde zu haben (niemals ein globales Passwort auf dem Rechner Ihres Kunden speichern).

+0

@ S.P.Floyd - Seanizer: Ich denke, das nicht zu verstehen. Auf diese Weise wird das Kennwort in der Datenbank.properties gespeichert, so dass jeder es lesen kann, stimmt nicht? – blow

+0

nicht, wenn database.properties z. dynamisch während der Bereitstellung erstellt. –

+0

Was meinst du genau mit "Deployment"? Deployment ist, wenn ich meine Software an den Benutzer freizugeben, bedeutet das? – blow

0

Ich hatte die gleiche Frage in letzter Zeit. Ich wollte eine Hash-Version des Kennworts in einer .properties-Datei speichern. Ich habe den Trick dank der vorherigen Optionen: Ich erweiterte die DelegatingDataSource und überging die getConnection([...]) Methoden.

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); 
    } 
} 

Dann ist hier, wie habe ich es in meinem 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> 

Wo datasource.hash eine Eigenschaft ist (aus einer .properties-Datei) gespeichert wie:

datasource.hash = 2e54b0667ef542e3398c55a08a4e04e69b9769e8 

Die Ebene Das Passwort befindet sich immer noch in Bytecode, aber nicht mehr direkt in einer .properties-Datei.

0

Vielen Dank für Ihre Post und Ihre Fragen.

Hoffnung für Besucher ist die technische Möglichkeit, Passwort durch das Lesen dieser Seite zu verschlüsseln. Eine wichtige Sache, die ich hier hinzufügen möchte, wenn Sie mit der Produktion zu tun haben, wird Ihnen definitiv empfehlen, einen "Secure Hash Algorithm" wie SHA-256 mit Salz zu verwenden. Sie können einen sicheren Hash-Algorithmus mit Salz als Industriestandard in Betracht ziehen.