2013-04-26 11 views
9

Chciałbym użyć Typesafe's Config w moim projekcie, ale nie chcę żadnych haseł w postaci zwykłego tekstu w żadnym pliku w systemie plików dowolnego serwera integracyjnego lub produkcyjnego. Ponadto nie chcę używać environment variables to store clear text passwords.Jak używać konfiguracji Typesafe w Scali z zaszyfrowanymi hasłami

Idealnie, chciałbym rozwiązanie podobne do JasyptEncryptablePropertyPlaceholderConfigurer dostępne na wiosnę, które pozwoli mi wyznaczyć niektóre wartości właściwości jako szyfrowane i system konfiguracji automatycznie odszyfrować je przed przekazaniem wartości do aplikacji. Chciałbym użyć magazynu kluczy JCE do przechowywania klucza i przekazania go do mojej aplikacji, ale jestem także otwarty na inne narzędzia, które używają bazy danych do przechowywania kluczy.

Czy udało się każdemu, aby projekt Typesafe Config działał w ten sposób?

Aktualizacja: sourcedelica całkowicie skrytykowała rozwiązanie, które polegało na przekazywaniu klucza jako zmiennej środowiskowej. Zmieniłem pytanie, aby poprosić o rozwiązanie korzystające z bezpieczniejszego sposobu obsługi kluczy.

Odpowiedz

7

Można spróbować stręczycielstwo klasa typesafe Config tak:

object ConfigPimping{ 
    implicit class RichConfig(conf:Config){ 
    def getPasswordString(path:String, encryptKey:String):String = { 
     val encrypted = conf.getString(path) 
     val decrypted = ... //do decripy logic of your choice here 
     decrypted 
    } 
    } 
} 

object ConfigTest{ 
    import ConfigPimping._ 
    def main(args: Array[String]) { 
    val conf = ConfigFactory.load() 
    val myPass = conf.getPasswordString("myPass", "myDecryptKey") 
    } 
} 

Następnie, dopóki RichConfig zawsze jest importowany i dostępny, można uzyskać dostęp do swojego zwyczaju decrpyt logiki haseł poprzez funkcję getPasswordString .

+0

Skończyło się na pisaniu narzędzia bardzo podobnego do tego. Przyjmuję twoją odpowiedź i podam więcej szczegółów na temat tego, co zrobiłem w mojej własnej odpowiedzi. – rzrelyea

+0

Więc, rzeleyea, czy możesz podać więcej szczegółów? :) – ericpeters

+0

@ericpeters, są tutaj http://stackoverflow.com/a/23587363/11256 –

2

Na ryzyko mówi ci coś, co już wiem ...

  • Nigdy nie przechowywać haseł - sklep i porównaj przeciwko hash zamiast
  • Zastosowanie Bcrypt dla skrótów haseł - to powolny, który jest dobre dla zabezpieczenia przed atakiem brute-force
  • Korzystanie z solą - w celu ochrony przed atakiem tęczy stylu tabeli
  • Użyj SSL (https) - aby zapobiec haseł z widzianym w klarowny


Oto przykład, który używa Mindrot jBCrypt library:

 
    def PasswordHash(name:String, pwd:String, version:Int = 1) : String = { 
    if(version == 2 && false) 
    { 
     // ANY CHANGES SHOULD BE MADE AS A NEW VERSION AND ADDED HERE 
     "" 
    } 
    else 
    { 
     import org.mindrot.jbcrypt.BCrypt  // jbcrypt-0.3m.jar 

     // Salt will be incorporated in the password hash 
     val salt = BCrypt.gensalt(12) // Default is 10, or 2**10 rounds. More rounds is slower. 

     BCrypt.hashpw((name + pwd), salt) 
    } 
    } 

    def VerifyPassword(name:String, pwd:String, hash:String, version:Int = 1) : Boolean = { 
    if(version == 1) 
    { 
     import org.mindrot.jbcrypt.BCrypt  // jbcrypt-0.3m.jar 

     BCrypt.checkpw((name + pwd), hash) 
    } 
    else 
     false 
    } 


> PasswordHash ("Johnny", "mojehasło")
res4: String = $ 2a $ $ 12 dHIlTL14.t37Egf7DqG4qePE446GzzhIUAVuewMfkhfK0xxw3NW6i

> VerifyPassword ("Johnny", "mojehasło", "$ 2a $ $ 12 dHIlTL14.t37Egf7DqG4qePE446GzzhIUAVuewMfkhfK0xxw3NW6i")
res5: Boolean = true

> VerifyPassword ("Johnny", "mommiespassword", "$ 2a $ $ 12 dHIlTL14.t37Egf7DqG4qePE446GzzhIUAVuewMfkhfK0xxw3NW6i")
res6: Boolean = false

za to, co Próbuję to zrobić, zakładam, że będziesz przechowywać "nazwę", "hash hasła" i "wersję hash" w swojej konfiguracji.

+9

Zgaduję, że OP chce przechowywać hasło do konfiguracji połączenia DB lub coś w tym stylu, nie przechowuj go dla uzyskania dostępu do kontroli. W takim przypadku musimy dokładnie wiedzieć, jakie jest hasło. –

+2

Brian Hsu ma rację. Potrzebuję móc odszyfrować hasło przechowywane w pliku konfiguracyjnym, aby móc uwierzytelnić się w bazie danych. – rzrelyea

+0

Pakiet javax.crypto będzie zawierał procedury szyfrowania/odszyfrowywania. Możesz sprawdzić, czy twoja baza danych obsługuje "zaufane połączenie". Byłby to bezpieczniejszy sposób łączenia się z bazą danych i nie wymagałby przechowywania hasła w konfiguracji. –

6

Jeśli chcesz przekazać klucz szyfrujący jako zmienną środowiskową, możesz przekazać wszystkie wrażliwe właściwości jako zmienne środowiskowe i nie martwić się o używanie szyfrowania bezpośrednio z biblioteką konfiguracyjną Typesafe.

Na przykład:

my.sensitive = ${FOO_ENV} 

Powiedziałeś, że nie chcesz używać zmiennych środowiskowych w celu przechowywania haseł tekstowych jasne, ale jeśli przechowywania klucza szyfrowania w zmiennej środowiskowej jest to równoważne.

Alternatywnie można użyć właściwości systemowej zamiast zmiennej środowiskowej. Na przykład uruchamiając aplikację, użyj -Dmy.sensitive=xxx.

Jeśli w końcu otrzymasz zaszyfrowane wartości do swojej konfiguracji, możesz użyć klasy opakowania, która będzie odszyfrowywać. I use a wrapper class, aby dodać metody takie jak optString do konfiguracji. Możesz dodać metodę taką jak decryptString.

Aby porozmawiać na temat zabezpieczania kluczy używanych podczas produkcji, zobacz moje pytanie: Securing passwords in production environment.

+0

Przegłosowałem twoją odpowiedź, ponieważ jest to uzasadniona krytyka mojego pytania. Jednak nie jest to dokładnie odpowiedź na moje pytanie, które pyta, jak używać zaszyfrowanych kluczy z narzędziami konfiguracyjnymi Typesafe. – rzrelyea

+0

Wystarczająco sprawiedliwe - dodał jeszcze jeden komentarz. – sourcedelica

4

Wybrałem ścieżkę zaproponowaną przez cmbaxter. Tutaj wstawiam przykładowy kod, ponieważ komentarze nie obsługują kodu.

dodałem jakieś specjalnej składni, do pliku konfiguracyjnego, więc jeśli chcę umieścić zaszyfrowanego hasła w moim pliku config to zrobić tak:

my-app-config{ 
    db-username="foo" 
    db-password="ENC(9yYqENpuCkkL6gpoVh7a11l1IFgZ0LovX2MBF9jn3+VD0divs8TLRA==)" 
} 

Uwaga „ENC()” otoki wokół zaszyfrowane hasło.

Potem zrobiłem fabrykę config, która zwraca obiekt DycryptingConfig zamiast config typesafe:

import rzrelyea.config.crypto.DecryptingConfig; 
import rzrelyea.config.crypto.KeyProvider; 

public class ConfigFactory{ 

public static final Config makeDecryptingConfig(com.typesafe.config.Config config, KeyProvider keyProvider){ 
    return new DecryptingConfig(config, keyProvider); 
} 

}

i tu jest kod na DecryptingConfig:

import java.security.Key;  
import static rzrelyea.config.Validators.require; 

public class DecryptingConfig extends rzrelyae.config.Config { 

    private final com.typesafe.config.Config config; 
    private final Decryptor decryptor; 

    public DecryptingConfig(com.typesafe.config.Config config, KeyProvider keyProvider){ 
     super(config); 
     require(keyProvider, "You must initialize DecryptingConfig with a non-null keyProvider"); 
     this.config = config; 
     final Key key = keyProvider.getKey(); 
     require(key, "KeyProvider must provide a non-null key"); 
     decryptor = new Decryptor(config.getString("crypto-algorithm"), key, config.getString("encoding-charset")); 
    } 

    @Override 
    public String getString(String s) { 
     final String raw = config.getString(s); 
     if (EncryptedPropertyUtil.isEncryptedValue(raw)){ 
      return decryptor.decrypt(EncryptedPropertyUtil.getInnerEncryptedValue(raw)); 
     } 
     return raw; 
    } 

Oczywiście, musielibyśmy zaimplementować własny obiekt rzrelyea.config.Config, własny EncryptedPropertyUtil, własny Decryptor i własny KeyProvider. Moja implementacja rzrelya.config.Config pobiera obiekt konfiguracyjny typesafe jako parametr konstruktora i przekazuje do niego wszystkie wywołania. DUŻO kodu kotła w nim! Ale pomyślałem, że lepiej jest przekazywać połączenia do interfejsu, niż rozszerzać com.typesafe.config.impl.SimpleConfig. Wiesz, preferujesz skład do dziedziczenia i kod do interfejsów, a nie implementacji. Możesz wybrać inną trasę.

+0

Jestem newbie do typesafe ... Chciałbym zobaczyć przykładowy kod roboczy ze szczegółami. Pomoże to zrozumieć cały proces ładowania – Sohan

Powiązane problemy