Jak zabezpieczyć hasła do bazy danych w PHP?

404

Kiedy aplikacja PHP nawiązuje połączenie z bazą danych, oczywiście musi podać login i hasło. Jeśli używam jednego loginu o minimalnym uprawnieniu do mojej aplikacji, PHP musi gdzieś znać ten login i hasło. Jaki jest najlepszy sposób zabezpieczenia tego hasła? Wygląda na to, że samo napisanie go w kodzie PHP nie jest dobrym pomysłem.

użytkownik18359
źródło
1
Aby być całkowicie bezpiecznym, musisz skonfigurować połączenie ssl, w przeciwnym razie każdy w Twojej sieci może nadal wąchać wpisane hasło.
Charles Ma
1
Czy masz na myśli hasła użytkownika lub hasło bazy danych użyte w ciągu połączenia?
Ozgur Ozcitak
4
Hasło bazy danych użyte w ciągu połączenia. Dzięki!
user18359,

Odpowiedzi:

238

Kilka osób błędnie odczytało to jako pytanie o sposób przechowywania haseł w bazie danych. To jest złe. Chodzi o to, jak przechowywać hasło, które pozwala dostać się do bazy danych.

Zwykle rozwiązaniem jest przeniesienie hasła z kodu źródłowego do pliku konfiguracyjnego. Następnie pozostaw administrację i zabezpieczenie tego pliku konfiguracyjnego administratorom systemu. W ten sposób programiści nie muszą wiedzieć nic o hasłach produkcyjnych i nie ma zapisu hasła w kontroli źródła.

użytkownik11318
źródło
8
Dzięki. Jeśli dobrze to zrozumiem, plik php będzie wtedy zawierać plik konfiguracyjny, umożliwiając mu użycie hasła. np. tworzę plik o nazwie „app1_db_cfg.php”, który przechowuje login, hasło i nazwę db. Następnie moja strona application.php zawiera „app1_db_cfg.php” i działam!
user18359,
28
Zgadzam się, że konfiguracja musi być odpowiednio chroniona. Jednak wiedza, jak to zrobić, leży w gestii administratorów systemu, a nie programistów. W tym przypadku nie zgadzam się co do wartości silnego szyfrowania. Jeśli nie możesz zabezpieczyć pliku konfiguracyjnego, co myślisz, że możesz chronić swoje klucze?
user11318,
10
Wolę używać konta bazy danych, które może uzyskiwać dostęp do bazy danych tylko z serwera WWW. A potem nie przejmuję się szyfrowaniem konfiguracji, po prostu przechowuję ją poza katalogiem głównym.
gnud,
11
Używam zmiennej środowiskowej apache, aby ustawić ścieżkę tak, aby nawet ścieżka do pliku była nieznana w kodzie źródłowym. Pozwala to również ładnie mieć inne hasło do programowania i produkcji w zależności od ustawień Apache na serwerze
Geedew
15
Należy pamiętać, że nawet pliki przechowywane poza katalogiem dostępnym w Internecie muszą zostać odczytane przez skrypt, który ich używa. Jeśli ktoś doda ten plik, a następnie zrzuci dane z pliku, zobaczy hasło.
Rick Mac Gillis
104

Jeśli hostujesz na serwerze innej osoby i nie masz dostępu poza katalogiem głównym, zawsze możesz umieścić hasło i / lub połączenie z bazą danych w pliku, a następnie zablokować plik za pomocą .htaccess:

<files mypasswdfile>
order allow,deny
deny from all
</files>
Kelen
źródło
3
Dzięki, właśnie tego szukałem.
David Gladfelter,
28
Zdecydowanie, ale jeśli ktoś ma dostęp do powłoki, i tak całe Twoje konto zostało przejęte.
kellen
4
Jest to zła praktyka, ponieważ możesz przypadkowo zatwierdzić swoje dane uwierzytelniające w repozytorium.
Porlune
2
@Ankit: Jeśli nieprzyjazny może przesłać plik na serwer i wykonać go, serwer nie jest poprawnie skonfigurowany.
kellen
6
@Porlune: programiści powinni sprawić, aby ich system kontroli wersji ignorował plik haseł, tzn. Używając .gitignore. Ale tak, należy zachować ostrożność w przypadku plików zawierających poufne dane.
kellen
45

Najbezpieczniejszym sposobem jest całkowite wyeliminowanie informacji zawartych w kodzie PHP.

Jeśli używasz Apache, oznacza to ustawienie szczegółów połączenia w pliku httpd.conf lub pliku wirtualnego hosta. Jeśli to zrobisz, możesz wywołać mysql_connect () bez parametrów, co oznacza, że ​​PHP nigdy nie wyświetli twoich informacji.

W ten sposób określasz te wartości w tych plikach:

php_value mysql.default.user      myusername
php_value mysql.default.password  mypassword
php_value mysql.default.host      server

Następnie otwórz połączenie MySQL w następujący sposób:

<?php
$db = mysqli_connect();

Lub tak:

<?php
$db = mysqli_connect(ini_get("mysql.default.user"),
                     ini_get("mysql.default.password"),
                     ini_get("mysql.default.host"));
Lars Nyström
źródło
1
Sprawdź poprawne wartości ini_get („wartości domyślne”) php.net/manual/en/class.mysqli.php
Val
4
tak, ale każdy użytkownik (lub haker wykorzystujący źle napisany skrypt php) może odczytać hasło przez ini_get().
Marki555
1
@ Marki555 but any user (or a hacker abusing badly written php script) can read the password via ini_get()Jak sobie z tym poradzić?
tonix
2
Marki555 mówi, że osoba atakująca, która potrafi uruchomić kod PHP, może również wywoływać funkcje PHP, co jest oczywiście prawdą i nie można nic z tym zrobić. Chciałbym również dodać, że nie stosuję się już do porad udzielonych w tej odpowiedzi, ale używam zmiennych środowiskowych. Koncepcja jest podobna: nie przechowuj swoich danych uwierzytelniających w kodzie, ale jakoś je wstrzykuj. Tak naprawdę nie ma znaczenia, czy używasz ini_get()lub getenv().
Lars Nyström
2
@DeepBlue Jeśli możesz wstrzyknąć ini_get (), możesz również wstrzyknąć file_get_contents (anypath). Tak długo, jak php ma sposób na uzyskanie hasła, tak samo będzie ze złośliwym kodem.
varesa 16.04.17
40

Przechowuj je w pliku poza katalogiem głównym.

da5id
źródło
29
A także, jak wspomniano w innym miejscu, poza kontrolą źródła.
Frank Farmer
6
moglibyśmy to uwzględnić? np. w PHP czy możemy to zrobić include('../otherDirectory/configfile.conf')?
Mt
1
Wszyscy sugerują przechowywanie poświadczeń poza wwwroot. Ok, rozumiem tło bezpieczeństwa. Ale jak powinien być przechowywany w kontroli wersji (przykładowa konfiguracja)? Zwykle wwwroot jest źródłem git repo, więc jeśli coś jest na zewnątrz - będzie poza VC. Wyobraź sobie, że nowy programista próbuje założyć lokalną instancję na potrzeby programowania - skąd miałby znać magię typu „weź ten plik, skopiuj na zewnątrz i wypełnij”?
The Godfather
@TheGodfather Idea polega na tym, że nowy programista powinien posiadać własne poświadczenia dla własnego środowiska programistycznego. Chociaż dobrą praktyką jest mieć plik Readme z instrukcjami lub komentarzami w kodzie wskazującymi, jak należy go skonfigurować (ale nie rzeczywiste dane).
PhoneixS,
@TheGodfather, plik readme?
Pacerier
35

W przypadku bardzo bezpiecznych systemów szyfrujemy hasło bazy danych w pliku konfiguracyjnym (który sam jest chroniony przez administratora systemu). Po uruchomieniu aplikacji / serwera aplikacja monituje administratora systemu o klucz deszyfrujący. Hasło bazy danych jest następnie odczytywane z pliku konfiguracyjnego, odszyfrowywane i przechowywane w pamięci do wykorzystania w przyszłości. Nadal nie jest w 100% bezpieczny, ponieważ jest przechowywany w odszyfrowanej pamięci, ale w pewnym momencie musisz nazwać go „wystarczająco bezpiecznym”!

pdavis
źródło
85
co jeśli administrator umrze?
Radu Murzea
36
@RaduMurzea to niedorzeczne. Kiedy dowiedziałeś się o śmierci Sys Admins? Są jak McDonalds, po prostu pojawiają się / znikają znikąd!
ILikeTacos
13
@Radu Murzea Wystarczy mieć 2 lub więcej administratorów, a następnie masz parzystość jak tablica rajdowa. Szanse na awarię więcej niż jednego dysku na raz są znacznie mniejsze.
element11
5
co z ponownym uruchomieniem serwerów? A co z czasem, w którym budzi się administrator, aby zmusić go do wpisania hasła w… etc. Etc. lol
John Hunt
1
Nie jestem pewien, co rozumiesz przez „przechowywane w pamięci”. Aplikacje internetowe PHP zazwyczaj nie przechowują niczego w pamięci dłużej niż czas potrzebny na odpowiedź na indywidualne żądanie wyświetlenia strony.
bdsl,
15

To rozwiązanie jest ogólne, ponieważ jest przydatne zarówno w aplikacjach o otwartym, jak i zamkniętym źródle.

  1. Utwórz użytkownika systemu operacyjnego dla swojej aplikacji. Zobacz http://en.wikipedia.org/wiki/Principle_of_least_privilege
  2. Utwórz zmienną środowiskową systemu operacyjnego (nie sesyjnego) dla tego użytkownika, używając hasła
  3. Uruchom aplikację jako ten użytkownik

Zalety:

  1. Nie sprawdzisz przypadkowo swoich haseł w celu kontroli źródła, ponieważ nie możesz
  2. Nie zepsujesz przypadkowo uprawnień do plików. Cóż, możesz, ale to nie wpłynie na to.
  3. Może być odczytany tylko przez użytkownika root lub tego użytkownika. Root może odczytać wszystkie twoje pliki i klucze szyfrowania.
  4. Jeśli korzystasz z szyfrowania, w jaki sposób bezpiecznie przechowujesz klucz?
  5. Działa na X-platformie
  6. Pamiętaj, aby nie przekazywać envvaru do niezaufanych procesów potomnych

Metodę tę sugerują Heroku, którzy odnoszą duże sukcesy.

Neil McGuigan
źródło
11

jeśli możliwe jest utworzenie połączenia z bazą danych w tym samym pliku, w którym przechowywane są poświadczenia. Wstaw poświadczenia w instrukcji connect.

mysql_connect("localhost", "me", "mypass");

W przeciwnym razie najlepiej jest rozbroić poświadczenia po instrukcji connect, ponieważ poświadczeń, które nie są w pamięci, nie można odczytać z pamięci ;)

include("/outside-webroot/db_settings.php");  
mysql_connect("localhost", $db_user, $db_pass);  
unset ($db_user, $db_pass);  
Bob Fanger
źródło
9
Jeśli ktoś ma dostęp do pamięci, i tak jesteś zepsuty. To bezcelowe fałszywe bezpieczeństwo. Poza webrootem (lub przynajmniej chronionym przez .htaccess, jeśli nie masz dostępu powyżej swojego webroota) jest jedyną bezpieczną opcją.
uliwitness
2
@uliwitness - To tak, jakby powiedzieć, że tylko dlatego, że ktoś może przebić zamek twojego centrum operacyjnego za pomocą palnika acetylenowego, oznacza to, że drzwi są również fałszywym zabezpieczeniem. Utrzymywanie poufnych informacji w jak najściślejszym zakresie zawsze ma sens.
Luke A. Leber
1
Co powiesz na echo $ db_user lub wydrukowanie $ db_pass? Nawet programiści z tego samego zespołu nie powinni być w stanie ustalić poświadczeń produkcyjnych. Kod nie powinien zawierać niczego do wydrukowania na temat danych logowania.
Mohammed Joraid
8

Twoje wybory są w pewnym stopniu ograniczone, ponieważ, jak mówisz, potrzebujesz hasła, aby uzyskać dostęp do bazy danych. Jednym ogólnym podejściem jest przechowywanie nazwy użytkownika i hasła w osobnym pliku konfiguracyjnym zamiast w skrypcie głównym. Następnie pamiętaj, aby przechowywać to poza głównym drzewem internetowym. Tak było, jeśli istnieje problem z konfiguracją sieci, który powoduje, że pliki php są po prostu wyświetlane jako tekst, a nie wykonywane, nie ujawniono hasła.

Poza tym jesteś na właściwej linii z minimalnym dostępem do używanego konta. Dodaj do tego

  • Nie używaj kombinacji nazwy użytkownika / hasła do niczego innego
  • Skonfiguruj serwer bazy danych, aby akceptował połączenia z hosta WWW tylko dla tego użytkownika (localhost jest nawet lepszy, jeśli baza danych znajduje się na tym samym komputerze) W ten sposób, nawet jeśli ujawnione zostaną poświadczenia, nie będą one przydatne dla nikogo, chyba że będą mieli inny dostęp do maszyna.
  • Ukryj hasło (nawet ROT13 to zrobi), nie zapewni to dużej ochrony, jeśli niektórzy uzyskają dostęp do pliku, ale przynajmniej uniemożliwi jego swobodne przeglądanie.

Piotr

Vagnerr
źródło
8

Wcześniej przechowywaliśmy DB / pass użytkownika w pliku konfiguracyjnym, ale od tego czasu przeszliśmy w tryb paranoiczny - przyjmując politykę Obrony w głębi .

Jeśli aplikacja zostanie naruszona, użytkownik będzie miał dostęp do odczytu pliku konfiguracyjnego, więc cracker może odczytać te informacje. Pliki konfiguracyjne można również złapać w kontrolę wersji lub kopiować wokół serwerów.

Przełączyliśmy się na przechowywanie zmiennych użytkownika / hasła w zmiennych środowiskowych ustawionych w Apache VirtualHost. Ta konfiguracja jest możliwa do odczytania tylko przez użytkownika root - mam nadzieję, że użytkownik Apache nie działa jako użytkownik root.

Wadą tego jest to, że teraz hasło jest w zmiennej Global PHP.

Aby ograniczyć to ryzyko, stosujemy następujące środki ostrożności:

  • Hasło jest szyfrowane. Rozszerzamy klasę PDO o logikę do odszyfrowywania hasła. Jeśli ktoś przeczyta kod, w którym nawiązujemy połączenie, nie będzie oczywiste, że połączenie jest ustanawiane za pomocą zaszyfrowanego hasła, a nie samego hasła.
  • Zaszyfrowane hasło jest przenoszone ze zmiennych globalnych do zmiennej prywatnej . Aplikacja robi to natychmiast, aby zmniejszyć okno dostępności wartości w przestrzeni globalnej.
  • phpinfo()jest niepełnosprawny. PHPInfo jest łatwym celem, aby uzyskać przegląd wszystkiego, w tym zmiennych środowiskowych.
Courtney Miles
źródło
6

Umieść hasło bazy danych w pliku i ustaw je jako tylko do odczytu dla użytkownika obsługującego pliki.

O ile nie masz środków pozwalających tylko procesowi serwera php na dostęp do bazy danych, to prawie wszystko, co możesz zrobić.

Chris
źródło
5

Jeśli mówisz o haśle bazy danych, w przeciwieństwie do hasła pochodzącego z przeglądarki, standardową praktyką jest umieszczanie hasła bazy danych w pliku konfiguracyjnym PHP na serwerze.

Musisz tylko upewnić się, że plik php zawierający hasło ma odpowiednie uprawnienia. Oznacza to, że powinien być czytelny tylko dla serwera WWW i konta użytkownika.

Jason Wadsworth
źródło
1
Niestety plik konfiguracyjny PHP może zostać odczytany przez phpinfo (), a jeśli ktoś porzuci jakiś skrypt testowy za szczęśliwym atakującym, będzie mógł odczytać hasło. Prawdopodobnie najlepiej pozostawić hasło połączenia w pliku poza katalogiem głównym serwera WWW. Wtedy jedynym sposobem na uzyskanie dostępu jest albo powłoka, albo wykonanie dowolnego kodu, ale w tym scenariuszu i tak utracono wszelkie zabezpieczenia.
MarioVilas
5

Zwykłe umieszczenie go w pliku konfiguracyjnym jest takie, jak zwykle. Upewnij się tylko, że:

  1. nie zezwalaj na dostęp do bazy danych z serwerów znajdujących się poza siecią,
  2. uważaj, aby przypadkowo nie pokazać hasła użytkownikom (w komunikacie o błędzie lub przez przypadkowe podanie plików PHP jako HTML itp.)
Marijn
źródło
5

Rozwiązaliśmy to w ten sposób:

  1. Użyj memcache na serwerze z otwartym połączeniem z innego serwera haseł.
  2. Zapisz, aby zapisać w pamięci podręcznej hasło (a nawet cały plik password.php zaszyfrowany) plus klucz odszyfrowujący.
  3. Strona internetowa wywołuje klucz memcache zawierający hasło pliku hasła i odszyfrowuje w pamięci wszystkie hasła.
  4. Serwer haseł wysyła nowy zaszyfrowany plik hasła co 5 minut.
  5. Jeśli używasz zaszyfrowanego hasła.php w swoim projekcie, przeprowadzasz audyt, który sprawdza, czy ten plik został dotknięty zewnętrznie - lub wyświetlony. Gdy tak się stanie, możesz automatycznie wyczyścić pamięć, a także zamknąć serwer w celu uzyskania dostępu.
Asi Azulay
źródło
4

Dodatkową sztuczką jest użycie osobnego pliku konfiguracyjnego PHP, który wygląda następująco:

<?php exit() ?>

[...]

Plain text data including password

Nie uniemożliwia to prawidłowego ustawienia reguł dostępu. Ale w przypadku włamania się do Twojej witryny „wymaganie” lub „dołączenie” po prostu wyjdzie ze skryptu w pierwszym wierszu, więc jeszcze trudniej jest uzyskać dane.

Niemniej jednak nigdy nie należy zezwalać na pliki konfiguracyjne w katalogu, do którego można uzyskać dostęp za pośrednictwem Internetu. Powinieneś mieć folder „Web” zawierający kod kontrolera, css, zdjęcia i js. To wszystko. Wszystko inne trafia do folderów offline.

e-satis
źródło
ale w jaki sposób skrypt php odczytuje poświadczenia zapisane w pliku?
Christopher Mahan
3
Używasz fopen (), jak w przypadku zwykłego pliku tekstowego.
e-satis
2
@ e-satis ok to zapobiegnie hakerowi require/ includeale jak temu zapobiec fopen?
dmnc
„nie przeszkadza to w prawidłowym ustawianiu zasad dostępu”
e-satis
@ e-satis, to całkiem sprytne. zastanawiam się, dlaczego nikt o tym nie pomyślał. Jednakże , wciąż narażone na problem redaktor kopii. feross.org/cmsploit
Pacerier
4

Najlepszym sposobem jest w ogóle nie przechowywać hasła!
Na przykład, jeśli korzystasz z systemu Windows i łączysz się z SQL Server, możesz użyć zintegrowanego uwierzytelnienia, aby połączyć się z bazą danych bez hasła, używając tożsamości bieżącego procesu.

Jeśli musisz połączyć się z hasłem, najpierw zaszyfruj je, używając silnego szyfrowania (np. Za pomocą AES-256, a następnie chroń klucz szyfrowania lub za pomocą szyfrowania asymetrycznego i system operacyjny chroni certyfikat), a następnie przechowuj w plik konfiguracyjny (poza katalogiem WWW) z silnymi listami ACL .

Zachłanny
źródło
3
Nie ma sensu ponownie szyfrować hasła . Ktoś, kto może dostać się do niezaszyfrowanego hasła, może również uzyskać hasło potrzebne do odszyfrowania hasła. Jednak korzystanie z list ACL i .htaccess jest dobrym pomysłem.
uliwitness
2
@uliwitness Myślę, że mogłeś źle zrozumieć - co rozumiesz przez „szyfruj ponownie ”? To tylko jedno szyfrowanie. I nie chcesz używać haseł (przeznaczonych do użytku przez ludzi) do ich szyfrowania, a raczej silne zarządzanie kluczami, np. Chronione przez system operacyjny, w taki sposób, że zwykły dostęp do systemu plików nie zapewni dostępu do klucza.
AviD
3
Szyfrowanie nie jest magiczne - zamiast chronić klucz AES za pomocą list ACL, możesz po prostu przechowywać tam hasło. Nie ma różnicy między dostępem do klucza AES a odszyfrowanym hasłem, szyfrowanie w tym kontekście jest po prostu olejem węża.
MarioVilas
@MarioVilas co? Jeśli hasło jest zaszyfrowane, a klucz szyfrujący jest chroniony przez system operacyjny, to jak nie ma różnicy? Szyfrowanie nie jest magią - po prostu skraca całą tajemnicę do mniejszego klucza szyfrowania. Prawie nie wężowy, w tym kontekście po prostu przenosi całą tę tajemnicę do systemu operacyjnego.
AviD
6
@AviD, dlaczego system operacyjny może chronić klucz, ale nie same dane? Odpowiedź: może chronić obie te funkcje, więc szyfrowanie tak naprawdę nie pomaga. Byłoby inaczej, gdyby tylko dane były przechowywane, a klucz szyfrowania pochodziłby na przykład z hasła, które musiał wpisać użytkownik.
MarioVilas