Czy przechowywanie haseł jako zmiennych środowiskowych (zamiast zwykłego tekstu) w plikach konfiguracyjnych jest bezpieczne?

109

Pracuję nad kilkoma aplikacjami w railsach, django (i trochę php), a jedną z rzeczy, które zacząłem robić w niektórych z nich, jest przechowywanie bazy danych i innych haseł jako zmiennych środowiskowych zamiast zwykłego tekstu w niektórych plikach konfiguracyjnych ( lub w settings.py, dla aplikacji django).

Dyskutując o tym z jednym z moich współpracowników, zasugerował, że jest to zła praktyka - być może nie jest to tak całkowicie bezpieczne, jak mogłoby się wydawać.

Więc chciałbym wiedzieć - czy to bezpieczna praktyka? Czy bezpieczniejsze jest przechowywanie haseł w tych plikach w postaci zwykłego tekstu (oczywiście nie pozostawiając tych plików w publicznych repozytoriach ani nic takiego)?

sójka
źródło

Odpowiedzi:

45

Na poziomie bardziej teoretycznym mam tendencję do myślenia o poziomach bezpieczeństwa w następujący sposób (w kolejności rosnącej siły):

  • Brak ochrony. Zwykły tekst. Każdy, kto wie, gdzie szukać, może uzyskać dostęp do danych.
  • Bezpieczeństwo dzięki zaciemnieniu. Przechowujesz dane (zwykły tekst) w jakimś trudnym miejscu, na przykład w zmiennej środowiskowej lub w pliku, który ma wyglądać jak plik konfiguracyjny. Atakujący w końcu dowie się, co się dzieje, lub natrafi na to.
  • Bezpieczeństwo zapewniane przez szyfrowanie, które jest łatwe do złamania (pomyśl o szyfrze Cezara!).
  • Bezpieczeństwo zapewnia szyfrowanie, które można złamać przy pewnym wysiłku.
  • Bezpieczeństwo zapewniane przez szyfrowanie, które jest niepraktyczne do złamania przy obecnym sprzęcie.
  • Najbezpieczniejszy system to taki, z którego nikt nie może korzystać! :)

Zmienne środowiskowe są bardziej bezpieczne niż plikach tekstu jawnego, ponieważ są one niestabilne / jednorazowy, nie zapisany; tj. jeśli ustawisz tylko lokalną zmienną środowiskową, taką jak „set pwd = cokolwiek”, a następnie uruchomisz skrypt z czymś, co zamyka powłokę poleceń na końcu skryptu, wówczas zmienna już nie istnieje. Twoja sprawa mieści się w dwóch pierwszych, co powiedziałbym, że jest dość niepewne. Gdybyś miał to zrobić, nie polecałbym wdrażania poza twoją bezpośrednią siecią intranetową / domową, a następnie tylko do celów testowych.

John Carter
źródło
1
Zależy to od systemu operacyjnego - w najlepszym przypadku zmienne środowiskowe są tak samo podatne jak pliki zwykłego tekstu, ale prawdopodobnie są gorsze. W przypadku plików w postaci zwykłego tekstu można ustawić uprawnienia do odczytu plików / katalogów, aby je chronić. IIRC dla zmiennych środowiskowych, żyją w przestrzeni pamięci dla procesu powłoki, więc przedsiębiorczy cracker może przeskanować tę przestrzeń w poszukiwaniu ich.
John Carter
1
poczekaj chwilę: jeśli przechowujesz poświadczenie w zmiennej środowiskowej, muszą najpierw się tam dostać. Albo ręcznie, albo za pomocą scenariusza. Aby zautomatyzować uruchamianie oprogramowania, polecam skrypt. Ale zgadnij co, to mimo wszystko musisz przechowywać je w pliku konfiguracyjnym (dla zmiennych env). O ile nie podajesz ręcznie wartości dla zmiennych env, nie widzę różnicy w zabezpieczeniach plików konfiguracyjnych.
matematyka
59

Jak wspomniano wcześniej, obie metody nie zapewniają żadnej warstwy dodatkowego „bezpieczeństwa” po przejęciu systemu. Uważam, że jednym z najsilniejszych powodów, dla których warto faworyzować zmienne środowiskowe, jest kontrola wersji : widziałem zbyt wiele konfiguracji bazy danych itp., Które były przypadkowo przechowywane w systemie kontroli wersji, takim jak GIT, aby każdy inny programista mógł to zobaczyć (i ups! ja również ...).

Brak przechowywania haseł w plikach uniemożliwia ich przechowywanie w systemie kontroli wersji.

wstyd
źródło
6
A całkiem rozsądną alternatywą do nie przechowywania tajnych ustawienia konfiguracyjne w kontroli wersji jest przechowywanie ich w repozytorium kontroli wersji projektu lub odrębny z repozytorium kodu.
Kenny Evitt
1
@KennyEvitt, który nadal pozostawia niezabezpieczone hasła w postaci zwykłego tekstu we współdzielonej lokalizacji, które każdy, kto ma dostęp do repozytorium, może znaleźć i nie ma możliwości śledzenia, kto miał do niego dostęp.
FistOfFury
2
@FistOfFury Jasne, każdy, kto ma dostęp do repozytorium ... może uzyskać dostęp do repozytorium. Celem przechowywania sekretów w oddzielnym repozytorium jest właśnie to, że można kontrolować dostęp do tych sekretów inaczej niż sam kod. Ale repozytoria mogą być zabezpieczone, np. Możesz przechowywać sekrety zaszyfrowane w „udostępnionej lokalizacji”. Możesz nawet śledzić informacje o dostępie do repozytorium we współdzielonej lokalizacji. Ale oczywiście zezwolenie każdemu na dostęp do informacji oznacza, że ​​mogą skopiować te informacje, a tym samym uzyskać do nich dostęp w dowolnym momencie w przyszłości bez ograniczeń lub śledzenia.
Kenny Evitt
2
Świetny powód, aby użyć rozwiązania do zarządzania konfiguracją, które pozwala przechowywać zaszyfrowane wpisy tajne, a następnie zastępować je w szablonach konfiguracji w czasie renderowania. Szef kuchni ma zaszyfrowane torby z danymi, Ansible ma sejfy itp.
Brian Cline
1
Nazywa się to zarządzaniem dostępem uprzywilejowanym, w którym sekrety są przechowywane w scentralizowanym skarbcu PAM z kompleksową kontrolą dostępu. Gartner wymienia niektóre takie produkty .
Amit Naidu
44

Zawsze, gdy musisz przechowywać hasło, jest to niebezpieczne. Kropka. Nie ma możliwości bezpiecznego przechowywania niezaszyfrowanego hasła. Teraz, która ze zmiennych środowiskowych w porównaniu z plikami konfiguracyjnymi jest bardziej „bezpieczna”, jest być może dyskusyjna. IMHO, jeśli twój system jest zagrożony, tak naprawdę nie ma znaczenia, gdzie jest przechowywany, sumienny haker może go wyśledzić.

Chris Pratt
źródło
12
W przypadku zmiennych środowiskowych spodziewam się tutaj unixa ... Zmienne środowiskowe są znacznie mniej bezpieczne niż pliki. Każdy może sprawdzić środowisko uruchomionego procesu, ale pliki mogą mieć przynajmniej listy ACL.
Vatine
11
Biorąc pod uwagę, że programista musi przechowywać te hasła, nie jest to szczególnie pomocna odpowiedź. Gdzie sugerujesz, że je przechowuje?
Peter Nixey,
2
@Vatine Miejsca ujawniające zmienne środowiskowe również mają uprawnienia. Spróbuj cat /proc/1/environna przykład.
Chris Down,
4
@Vatine Naprawdę? Nie widzę środowiska dla procesów, które nie są moją własnością ps axe. strace -e open ps axepokazuje, że pobiera te informacje /proc/[pid]/environ, które wymuszają uprawnienia (stąd kilka open("/proc/19795/environ", O_RDONLY) = -1 EACCES (Permission denied)).
Chris Down
4
Huh. Spójrz na to, problem został w końcu naprawiony (kiedyś psbył on rozwiązany i z radością pokazałby ci środowisko prawie wszystkiego).
Vatine
28

Przepraszam, że nie miałem wystarczającej liczby przedstawicieli, aby komentować, ale chciałem również dodać, że jeśli nie będziesz ostrożny, twoja powłoka może również przechwycić to hasło w historii poleceń. Więc uruchamianie czegoś takiego jak $ pwd=mypassword my_progręczne nie jest tak efemeryczne, jak można by się spodziewać.

brianclements
źródło
21
jeśli poprzedzisz całe polecenie „env var +” spacją, nie zostanie ono zapisane w historii
shadi
dzięki @shadi. Dowiedz się czegoś nowego każdego dnia! Zastanawiam się, czy jest to specyficzne dla powłoki / łatwe do wyłączenia, czy może jest to coś, czego można się spodziewać dość konsekwentnie?
brianclements,
4
Innym sposobem jest użycie, read -s MY_PASS_VARktóre będzie chronić zarówno przed przeszukiwaniem historii muszli, jak i przed surferami.
MatrixManAtYrService
4
@brianclements Chciałbym dodać, że prefiksowanie polecenia spacją działa tylko wtedy, gdy bieżąca powłoka HISTCONTROLjest ustawiona na ignorespacelub ignoreboth, więc technicznie można ją włączyć / wyłączyć.
Mojżesz
14

Myślę, że jeśli to możliwe, powinieneś przechowywać swoje poświadczenia w pliku gitignored, a nie jako zmienne środowiskowe.

Jedną z rzeczy do rozważenia podczas przechowywania poświadczeń w zmiennych ENV (środowiskowych) w porównaniu z plikiem jest to, że zmienne ENV można bardzo łatwo sprawdzić za pomocą dowolnej biblioteki lub zależności, których używasz.

Można to zrobić złośliwie lub nie. Na przykład autor biblioteki może przesłać ślady stosu oraz zmienne ENV do siebie w celu debugowania (nie jest to najlepsza praktyka, ale można to zrobić).

Jeśli twoje poświadczenia znajdują się w pliku, zajrzenie do nich jest znacznie trudniejsze.

W szczególności pomyśl o npm w węźle. Aby npm spojrzał na twoje poświadczenia, jeśli znajdują się one w ENV, to prosta sprawa process.ENV. Jeśli z drugiej strony są w pliku, to dużo więcej pracy.

To, czy plik danych logowania jest kontrolowany przez wersję, czy nie, to osobna kwestia. Brak wersji kontrolującej plik poświadczeń udostępnia go mniejszej liczbie osób. Nie ma potrzeby, aby wszyscy programiści znali referencje produkcyjne. Ponieważ jest to zgodne z zasadą najniższych przywilejów, sugerowałbym git zignorowanie twojego pliku poświadczeń.

Peter Ajtai
źródło
6
+1 dla „autor biblioteki może wysłać do siebie ślady stosu oraz zmienne ENV w celu debugowania”. Nigdy nie myślałem o tym scenariuszu.
Netishix
6

To zależy od modelu zagrożenia.

Czy starasz się uniemożliwić użytkownikom rozsypywanie haseł we wszystkich systemach plików, gdzie mogą zostać zapomniane i niewłaściwie użyte? Jeśli tak, to tak, ponieważ zmienne środowiskowe są mniej trwałe niż pliki.

Czy próbujesz zabezpieczyć się przed złośliwym oprogramowaniem, które jest bezpośrednio skierowane do Twojego programu? Jeśli tak, to nie, ponieważ zmienne środowiskowe nie mają takiego samego poziomu kontroli dostępu, jak pliki.

Osobiście uważam, że niedbali użytkownicy są bardziej powszechni niż zmotywowani przeciwnicy, więc wybrałbym podejście oparte na zmiennych środowiskowych.

MatrixManAtYrService
źródło
0

AFAICT, istnieją dwa powody, dla których ludzie zalecają przechowywanie sekretów w zmiennych środowiskowych:

  1. Zbyt łatwo jest nieumyślnie przekazać tajne płaskie pliki do repozytorium. (A jeśli jest to publiczne repozytorium, jesteś tostem).
  2. Zapobiega bałaganowi w hasłach, tj. Posiadanie tego samego klucza w wielu różnych plikach katalogu projektu samo w sobie stanowi zagrożenie bezpieczeństwa, ponieważ programiści ostatecznie stracą orientację, gdzie znajdują się sekrety.

Te dwa problemy można rozwiązać w lepszy sposób. To pierwsze powinno zostać rozwiązane przez hak git commit, który sprawdza rzeczy, które wyglądają jak hasła (np. Gitleaks ). Chciałbym, żeby Linus wbudował takie narzędzie w kod źródłowy biblioteki git, ale niestety tak się nie stało. (Nie trzeba dodawać, że tajne pliki powinny być zawsze dodawane .gitignore, ale potrzebujesz haka na wypadek, gdyby ktoś o tym zapomniał.)

Ten ostatni można rozwiązać, mając globalny plik tajnych firm, który najlepiej jest przechowywany na dysku współdzielonym tylko do odczytu. Więc w Pythonie możesz mieć coś takiego jak from company_secrets import *.

Co ważniejsze, jak podkreślają inni, zbyt łatwo jest zhakować sekrety przechowywane w zmiennych środowiskowych. Na przykład w Pythonie autor biblioteki mógłby wstawić, send_email(address="[email protected]", text=json.dumps(os.environ))a następnie wykonać toast, jeśli wykonasz ten kod. Hakowanie jest znacznie trudniejsze, jeśli masz w systemie plik o nazwie ~/secret_company_stuff/.my_very_secret_company_stuff.

Tylko użytkownicy Django:
Django (w trybie DEBUG) pokazuje surową wartość zmiennej środowiskowej w przeglądarce, jeśli jest wyjątek (w trybie DEBUG). Wydaje się to wysoce niepewne, jeśli na przykład programista przypadkowo rozpoczyna DEBUG=Trueprodukcję. W przeciwieństwie do tego, Django CZY zaciemniać ustawienia hasła zmienne szukając strun API, TOKEN, KEY, SECRET, PASSlub SIGNATUREw ramach za settings.pynazwami zmiennych pliku.

pandichef
źródło