linio@terramail.pl Uszczelnić PHP wersja 0.4 1. Było sobie PHP Większość dokumentów czy książek zaczyna się od definicji PHP i jego historii. Dlatego tutaj tego nie będzie. Potężne możliwości jakie oferuje ten język nie pozostają bez wpływu na bezpieczeństwo całego systemu. Poruszając temat bezpieczeństwa PHP możemy wyróżnić trzy najważniejsze elementy: instalacja, konfiguracja, programowanie. Instalacja: najważniejszym wydaje się być aktualna wersja oprogramowania serwera (PHP, Apache, mod_ssl itp.) oraz oprogramowania użytkowego ( poczta przez www, tablica ogłoszeń itd.). Bezpieczeństwo w znaczący sposób zwiększa uwięziony (ang. chrooted) Apacz. A kto może sobie na to pozwolić (np. firmy państwowe) stawia dedykowany serwer www. Tą kwestię poruszymy na szybkiego ograniczając się do krótkiego opisu instalacja Apacza z PHP. Konfiguracja: główny cel niniejszego dokumentu to przedstawienie różnych opcji konfiguracyjnych działającego serwera www z PHP (pliki php.ini oraz httpd.conf). Chodzi nam o ograniczenie stosunkowo niebezpiecznych elementów języka nie ograniczając przy tym funkcjonalności samego serwera. Programowanie: możemy wykorzystywać gotowe programy, możemy je pisać lub pisać mogą je inni. Dobrze jest znać przynajmniej podstawy pisania w PHP oraz najczęściej pojawiające się błędy. Przedstawione zostaną w tej pracy podstawowe rzeczy związane z bezpieczeństwem. Sposób konfiguracji naszego serwera zależy od funkcji, którą on pełni. Czy tylko my korzystamy z PHP, czy każdy może to robić, czy bawimy się na maszynie w domu czy też na serwerze przemysłowym. Jako administrator powinieneś najlepiej wiedzieć kto powinien móc co zrobić na maszynie będącej pod Twoją opieką. Okej, wystarczy tego marudzenia. 2. Instalujemy potrzebny soft Na początek powinniśmy zadbać o ściągnięcie ostatnich stabilnych wersji Apacza oraz PHP. Oto potrzebne linki: http://httpd.apache.org http://php.net 1
W chwili pisania pierwszej wersji tego dokumentu aktualnymi wersjami były apache_1.3.28 oraz php-4.3.2. Na nich oprę dalszą część pracy. A teraz odnośnie możliwości połączenia Apacza z PHP. Otóż można to zrobić na dwa sposoby: jako moduł CGI oraz jako moduł Apacza (statyczny lub dynamiczny). Pierwszy z nich polega na tym, że nasze skrypty przekazywane są do interpretera PHP, zewnętrznego programu. Rozwiązanie to uważane jest za mniej bezpieczne i wolniejsze od modułu Apacza. Praca jako moduł serwera www jest szybsza (i bardziej wydajna w przypadku modułu statycznego). W ten właśnie sposób przygotujemy naszego Apacza. Na początku utworzę sobie użytkownika i grupę z których prawami będzie działał serwerek www. Wybór padł na użytkownika www i grupę www. Oto potrzebne polecenia: groupadd www useradd -c "serwer www" -d /dev/null -g www -s /bin/false www Po rozpakowaniu wcześniej wymienionych plików podaję, co następuje: cd apache_1.3.28/./configure cd.. cd php-4.3.2/./configure --with-apache=../apache_1.3.28 --without-mysql --without-pgsql make make install cd.. cd apache_1.3.28/./configure --prefix=/usr/local/apache --sysconfdir=/etc/apache --activate-module=src/modules/php4/libphp4.a --server-gid=www --server-uid=www make make install cd.. cd php-4.3.2/ cp php.ini-dist /usr/local/lib/php.ini Pozostało już tylko wrzucić do edytora plik konfiguracyjny Apacza (tutaj: /etc/apache/httpd.conf) i dopisać: AddType application/x-httpd-php.php Dobrze jest także sprawdzić parametr Port (zalecana wartość: 80) oraz User i Group (tutaj wartością powinno być www). Nasz serwer możemy uruchomić poleceniem: /usr/local/apache/bin/apachectl start I jeszcze dwa słowa wyjaśnienia: przygotowując PHP do kompilacji wyłączyłem przypadkowe wykrycie MySQL i PostgreSQL. Po prostu nie potrzebuję ich na razie w PHP i tyle. Opcje te możesz pominąć, ewentualnie włączyć jedną z nich. 2
Jeszcze coś: dobrze jest dopisać w pliku httpd.conf nazwę indeksowego (startowego) pliku.php (np. index.php). DirectoryIndex index.html index.php Teraz po przeładowaniu Apacza (/usr/local/apache/bin/apachectl restart) plikiem startowym może być index.php. Wypadałoby jeszcze sprawdzić, czy nasz Apacz z PHP działa. Tworzymy sobie plik testowy (np. touch /usr/local/apache/htdocs/test.php) a następnie umieszczamy w nim: <? phpinfo();?> Po wpisaniu do przeglądarki www adresu naszego serwera (np. http://localhost/test.php) powinniśmy ujrzeć wiele ciekawych informacji :) Jak wspomniałem wcześniej, instalacja omówiona została w dużym skrócie. Założyłem także, że wiesz do czego służą niektóre opcje w pliku httpd.conf. Jest wiele dokumentów w Sieci na temat konfiguracji samego Apacza i byłoby dobrze, gdybyś znał najważniejsze z nich. Wspomnę tylko, że może okazać się przydatne polecenie: /usr/local/apache/bin/apachectl configtest Celem tego wszystkiego jest otrzymanie działającego Apacza z PHP. Naszym najważniejszym plikiem będzie /usr/local/lib/php.ini i konfiguracja samego PHP. W dalszej części zakładam, że masz podstawowe pojęcie o httpd.conf oraz programowaniu w PHP. 3. register_globals od tego się zaczyna Plik konfiguracyjny PHP to /usr/local/lib/php.ini. Znajduje się w nim większość opcji mających wpływ na sposób, w jaki PHP działa. Po każdej zmianie w tym pliku należy przeładować Apacza (apachectl restart). register_globals = Off Wartość zalecana i domyślna od wersji 4.2.0 PHP. Swojego czasu było to główne źródło problemów związanych z bezpieczeństwem języka. Ustawienie tej wartości na On powoduje, że wszystkie zmienne wysłane do skryptu tworzone były jako globalne nadpisując wcześniej ustalone wartości tych zmiennych lub tworząc zmienne jeszcze nie istniejące w skrypcie a wykorzystywane w nim później. Przykładem wykorzystywania tego faktu było np. oszukiwanie mechanizmów autoryzacji. 3
Zmiana domyślnej wartości tej opcji na Off, oprócz zwiększenia bezpieczeństwa spowodowała małą rewolucję w świecie PHP: programiści (idący zazwyczaj na jeszcze większą łatwiznę niż administratorzy) musieli przyzwyczaić się do nowego sposobu odwoływania do zmiennych a duża część istniejących programów musiała zostać poprawiona. Z punktu widzenia programisty wyłączenie tej opcji oznacza: odwołując się do zmiennej nazwisko zamiast $nazwisko używaj $HTTP_POST_VARS[ nazwisko ] lub jego skróconej formy $_POST[ nazwisko ]. Dla danych wysyłanych jako GET, należy użyć odpowiednio $HTTP_GET_VARS[ nazwisko ] i $_GET[ nazwisko ]. Osoby poznające dopiero PHP powinny poznać ten sposób odwoływania się do przesłanych zmiennych jako jedyny słuszny sposób. Podsumowując: register_globals = Off spowoduje, że PHP nie utworzy żadnych zmiennych globalnych nie zdefiniowanych w skrypcie explicite. Jest to wartość domyślna w obecnych wersjach PHP, w znaczny sposób zwiększająca bezpieczeństwo a także zalecana. 4. Admin daje, admin zabiera PHP jest dobrodziejstwem, na które użytkownicy powinni sobie zasłużyć :) Zaraz po instalacji a przed konfiguracją dobrze jest wyłączyć PHP dla użytkowników i ograniczyć jego działanie do określonych katalogów. Do takich i podobnych działań na tle konfiguracyjnym możemy posłużyć się flagami PHP. W pliku php.ini znajduje się wiele opcji konfiguracyjnych. Dotyczą one całego PHP a więc zmiany tam wprowadzone dotyczą wszystkich katalogów (stron) udostępnianych przez naszego Apacza: strony głównej naszego serwera, wirtualnych hostów oraz stron użytkowników. Flagi PHP umieszcza się w pliku httpd.conf w sekcji dotyczącej określonego katalogu i właśnie ich dotyczą wprowadzane zmiany. Możemy wyróżnić dwa rodzaje flag: dotyczące ustawień logicznych (coś działa lub nie On / Off) a także ustawień, które posiadają inne niż logiczne wartości, np. nazwa pliku lub katalogu. Mamy więc odpowiednio: php_admin_flag nazwa On/Off php_admin_value nazwa wartość I tak na przykład flaga logiczna engine odpowiada za to, czy PHP działa (interpretuje pliki.php) czy też nie. Niech główna strona naszego serwera www będzie pobierana z katalogu /usr/local/apache/htdocs/ (tak jest standardowo). Niech znajduje się tam plik index.php o zawartości: <??> phpinfo(); 4
Po połączeniu się z główną stroną naszego serwera www (np. http://localhost) powinniśmy zobaczyć wynik działania funkcji phpinfo(). A teraz do pliku httpd.conf dopiszmy w określonym miejscu: php_admin_flag engine Off Ma to wyglądać mniej więcej tak: <Directory "/usr/local/apache/htdocs">.. php_admin_flag engine Off.. </Directory> Po przeładowaniu Apacza (apachectl restart) wejdźmy jeszcze raz na naszą stronę główną. I co? Nic. Przynajmniej tak powinno być strona główna naszego serwera www powinna być pusta, ponieważ PHP zostało dla niej (i jej podkatalogów) wyłączone. Już pewnie czaisz, że umieszczenie tego wpisu dla katalogów użytkowników Twojego serwera wyłączy im PHP: <Directory "/home/*/public_html > php_admin_flag engine Off </Directory> Oczywiście powyższy przykład zakłada standardowy katalog na strony www użytkowników public_html. A więc sprawa wygląda tak, że możemy wyłączyć PHP dla danych katalogów (i jego podkatalogów) a więc strony głównej, hostów wirtualnych, użytkowników. A co zrobić, żeby PHP było domyślnie wyłączone i dopiero ręczne włączenie za pomocą flag dla odpowiednich katalogów je uruchamiało? Nic prostszego: <Directory /> php_admin_flag engine Off </Directory> Wpis dla wszystkich katalogów (Directory /) znajduje się gdzieś na początku httpd.conf. Umieszczenie w nim powyższego wyłączy dla całego serwera www interpreter PHP i dopiero umieszczenie w odpowiednim miejscu php_admin_flag engine On włączy PHP. Paniał? Inne flagi logiczne to na przykład: asp_tags, display_errors, file_uploads itd. spójrz w to, co zwróci phpinfo() we flagach logicznych możesz przebierać. Drugi rodzaj flag ( wartościowe ) stosuje się analogicznie w odniesieniu do katalogu dla którego coś zmieniamy, np. php_admin_value auto_append_file dodatki.php. Może nie jest to najlepszy przykład, ale zasada działania identyczna: jeśli coś ma wartość On/Off stosujemy php_admin_flag, jeśli wartość jest liczbowa czy znakowa: php_admin_value. Jeszcze raz odsyłam do tego, co zwraca phpinfo() flag jest sporo. Tak więc przy pomocy flag możemy indywidualnie, dla danych katalogów (i skryptów w nich zainstalowanych) zmieniać własności PHP. Jeśli trzeba, możesz przy pomocy flag włączyć na przykład register_globals dla danego katalogu, pozostawiając resztę systemu bez tego. 5
To jeszcze nie koniec z flagami. Często istnieje potrzeba, żeby dla określonego katalogu (np. hosta wirtualnego) użytkownik sam mógł zmieniać niektóre flagi PHP. Oczywiście i to można zrobić ale trzeba się odpowiednio zabezpieczyć. Przykład: niech katalog /usr/local/apache/htdocs/firma_pl/ będzie katalogiem głównym dla jakiegoś hosta wirtualnego. Osoba tworząca tą stronę chce móc zmieniać niektóre flagi PHP (może to być na przykład auto_prepend_file, include_path czy coś w tym stylu). Wpis w httpd.conf powinien wyglądać następująco: <Directory /usr/local/apache/htdocs/firma_pl/ > AllowOverride Options </Directory> Jak już pewnie się domyślasz, do zmiany wartości flag posłuży plik.htaccess. Użytkownik umieszcza w nim potrzebne flagi razem z ich wartościami. I teraz tak: PHP działającego w katalogu /usr/local/apache/htdocs/firma_pl/ mogą dotyczyć już pewne flagi ustawione wcześniej przez administratora. Użytkownik nie może nadpisać wartości flag php_admin_flag oraz php_admin_value. Może on natomiast nadpisać wartości flag uwaga php_flag oraz php_value. Podsumowując: oto jak może wyglądać httpd.conf dla danego katalogu: <Directory /usr/local/apache/htdocs/firma_pl/ > AllowOverride Options # tych flag nie nadpisze: php_admin_flag register_globals Off php_admin_flag file_uploads Off # a to może php_flag asp_tags Off </Directory> I oto przykładowy.htaccess wrzucony do /usr/local/apache/htdocs/firma_pl/: php_flag asp_tags On php_value auto_prepend_file dodatki.php A jak klient przestanie płacić za miejsce na Twoim serwerze możesz do httpd.conf, do jego sekcji dopisać php_admin_flag engine Off. AllowOverride Options (lub AllowOverride All) w httpd.conf umożliwiają poprzez plik.htaccess nadpisanie pewnych standardowych opcji PHP Twojego serwera użytkownikom. Może dotyczyć to dowolnych katalogów (domowych użytkowników czy hostów wirtualnych). Wykorzystują oni w tym celu flagi php_flag i php_value. Możesz im jednak narzucić wartości niektórych opcji wykorzystując php_admin_flag i php_admin_value. Możesz także w httpd.conf wykorzystać flagi php_flag i php_value jednak użytkownicy, którym pozwolisz na swoje definicje, nadpiszą te standardowe. Tak czy siak, flagi php_admin_* nie zostaną przez nich nadpisane. 6
5. Co może użytkownik? Wbrew pozorom dużo. Weźmy typową sytuację, kogoś kto chce na naszym serwerze mieć założone konto i swoją stronę www (wykonaną oczywiście w PHP). Nasz nowy użytkownik otrzymuje login, katalog domowy, pusty shell (np. /bin/false) oraz dostęp przez FTP (jego / jest katalog domowy) a my jesteśmy szczęśliwi bo postawił przy okazji kilka piw. Co może nam zrobić, gdy nie ma shella? Pewnie nawet nie wie, jakim systemie i sprzęcie pracuje nasz serwerek. Niech jego loginem będzie zdzichu, katalogiem domowym /home/zdzichu, podkatalogiem jego strony www: public_html. Niech jego shellem będzie /bin/false. Tak więc Zdzichu łączy się przez FTP z naszym serwerem i wrzuca do podkatalogu public_html następujący plik index.php: <? $polecenie1="/bin/dmesg"; $polecenie2="/bin/netstat -a"; $plik="/etc/passwd"; system($polecenie1); print "<br><br>"; passthru($polecenie2); print "<br><br>"; readfile($plik); print "<br><br>"; phpinfo();?> Uważaliśmy Zdzicha za ciotę (pewnie przez twarz i zachowanie podobne do Ryśka z Klanu ), tymczasem he runs the show. Wie teraz więcej niż my o naszym serwerze i przy okazji udostępnia te informacje innym. Nieeeee... tak dalej być nie może. Co zrobił Zdzichu? Wykonał pewne polecenia systemowe, odczytał ważny plik i wykorzystał funkcję zwracającą wiele informacji o naszym serwerze. Dostęp do plików Zdzichu otworzył plik /etc/passwd. Równie dobrze mógłby otworzyć każdy inny plik na dysku serwera, który ma r dla wszystkich. Rozwiązaniem tego problemu jest funkcja safe_mode. Jest to jedna z najważniejszych funkcji PHP związanych z bezpieczeństwem. Umieszczenie w pliku php.ini zapisu: safe_mode = On spowoduje, że skrypty dostaną dostęp tylko do tych plików, których właściciel jest identyczny z właścicielem skryptu. Jeśli powyższy index.php należy do Zdzicha, skrypt będzie mógł otworzyć tylko pliki, których właścicielem jest Zdzichu. 7
Funkcje Dochodzimy do miejsca, w którym należy wyłączyć pewne funkcje. Służy temu opcja disable_functions. Jej argumentami są funkcje, które nie powinny być dostępne. Naszymi kandydatami są takie, umożliwiające na różne sposoby wykonanie poleceń systemowych: disable_functions = exec, passthru, system, popen; Dobrze jest dopisać do tej listy funkcję phpinfo. I każdą inną stanowiącą Twoim zdaniem zagrożenie dla systemu. Oto na przykład funkcje mogące służyć otworzeniu pliku (o ile mamy włączony safe_mode nie stanowi to takiego problemu): fopen, readfile, file. Ważna uwaga: przy włączonym safe_mode polecenia systemowe (przy pomocy wymienionych wyżej funkcji) są i tak wyłączone. Podsumowując: disable_functions wyłącza dla całego systemu wykonywanie pewnych funkcji, np. phpinfo(). Natomiast włączony safe_mode nie pozwoli na otworzenie plików, które mają innego właściciela niż skrypt a także wyłącza wykonywanie poleceń systemowych (np. /bin/netstat). A co jeśli pracując w trybie safe_mode niektóre polecenia systemowe są niezbędne? Wówczas należy posłużyć się opcją safe_mode_exec_dir. Definiuje ona katalog, z którego wykonywane będą polecenia systemowe w trybie safe_mode. Załóżmy więc, że Zdzichowi niezbędne jest polecenie /usr/bin/banner. Zdzichu pracuje w trybie safe_mode, dlatego należy: - utworzyć katalog dla binarek dostępnych z PHP w safe_mode: mkdir /bin/php - do php.ini dopisać ścieżkę do tego katalogu: safe_mode_exec_dir=/bin/php - skopiować plik do odpowiedniego katalogu: cp /usr/bin/banner /bin/php/ - przeładować Apacza apachectl restart Po takich zmianach Zdzichu może użyć system( /bin/php/banner dupa ) skrypcie PHP o ile disable_functions nie wyłączyło funkcji system. w swoim Podsumowując raz jeszcze: pracując w trybie safe_mode możemy (przy pomocy takich funkcji jak system) uruchamiać tylko binarki z safe_mode_exec_dir. Przy okazji disable_functions nie może wyłączyć funkcji system. Ostatecznie: zaleca się włączenie safe_mode a także ograniczenie niektórych funkcji (np. phpinfo) przy pomocy disable_functions. Pamiętaj, że możesz zmieniać wyżej wymienione opcje dla poszczególnych katalogów przy pomocy flag w pliku httpd.conf. Istnieje jeszcze jedna funkcja warta wspomnienia: open_basedir. Znajduje ona najczęściej zastosowanie w hostach wirtualnych: ogranicza ona wszystkie otwierane pliki (w tym i same skrypty.php) do określonego katalogu i jego podkatalogów. Nie dotyczy to plików wykonywanych przy pomocy np. system. Nie będę jej dokładnie opisywał. 8
6. Funkcyi kilka Ta część pracy skierowana jest do początkujących programistów. Przedstawię kilka podstawowych funkcji związanych z szeroko pojętym bezpieczeństwem. Założenie - jest sobie strona www z formularzem: wpisuje się nazwisko poszukiwanej osoby, naciska przycisk szukaj i czeka na wyniki. Wpisane nazwisko skierowane zostaje do skryptu PHP, który przeszukuje bazę danych i zwraca wyniki. To, co wpisze użytkownik pojawia się w skrypcie jako zmienna nazwisko. Strona z wynikiem poszukiwań zaczyna się od zdania Wynik poszukiwań dla.... W miejscu kropek powinno pojawić się to, co użytkownik wklepał do formularza. Oto najprostsze rozwiązanie: <? echo "Wynik poszukiwań dla "; echo $_POST['nazwisko'];;?> Działa... ale nie do końca. Spróbuj jako nazwisko wpisać <h1>noooowak</h1>. O to chodzi wszystko się spartoli. Funkcje, które mogą się przydać to htmlspecialchars() i strip_tags(). Pierwsza z nich powoduje zamianę tagów htmla do postaci nie interpretowanej przez przeglądarkę. Druga z nich po prostu usuwa tagi w rezultacie otrzymamy ascii. Rozwiązania: echo htmlspecialchars($_post['nazwisko']); echo strip_tags($_post['nazwisko']); w zależności od potrzeb. Dobra, wyświetlanie wprowadzonych danych mamy z głowy. Teraz dobrze by było, żeby po wysłaniu do bazy zwrócony został właściwy wynik. Jeszcze nie chodzi mi o samego SQLa tylko o przypadkowe naciśnięcie takich klawiszy jak spacja czy tabulator przed i po wpisanym nazwisku. Do obcięcia białych znaków przed i po szukanym wyrazie / wyrażeniu służy funkcja trim(). W naszym przypadku więc: $nazwisko = trim($_post['nazwisko']); Od tej pory posługujemy się zmienną $nazwisko. Tia... Nadszedł czas żeby wysłać zapytanie SQLowe do bazy danych. Jeśli osoba wprowadzająca dane do formularza użyje wystarczającej liczby cudzysłowów, średników i innych dziwnych rzeczy a my to żywcem wkleimy do zapytania a następnie wyślemy je do bazy możemy się z nią pożegnać. Coś takiego nazywane jest SQL Injection. Oszczędzam Tobie przykładów żeby nie zanudzać. Lepiej zobaczyć rozwiązanie. 9
Dla danych znakowych (jak w naszym przypadku) należy przekształcić wszystkie znaki będące na służbie SQLa na ich nic nie znaczące odpowiedniki. Mechanizm polega na tym, że przed owymi znakami stawiane są inne. Powodują one, że te pierwsze tracą na znaczeniu i do bazy trafiają zabezpieczone dane wprowadzone przez użytkownika. Przed wysłaniem zmiennej do bazy wykorzystuje się funkcję addslashes(). Po odczycie danych z bazy należy usunąć dodatkowe znaki wykorzystując funkcję stripslashes(). U nas wyglądałoby to tak: $nazwisko = addslashes($nazwisko); $nazwisko = stripslashes($nazwisko); (teraz można $nazwisko wysłać do bazy) (po odczycie z bazy) Przed wysłaniem danych numerycznych do bazy należy sprowadzić je do postaci numerycznej (żeby nie wysłać bzdur do pól numerycznych w bazie). I tak dla liczb całkowitych wykorzystuje się funkcję intval() a dla ułamkowych doubleval(). Gdyby użytkownik musiał wpisać wiek osoby i jej średnie zarobki użylibyśmy odpowiednio: $wiek = intval($wiek); $siano = doubleval($siano); W przypadku danych numerycznych nie ma problemu przy odczycie ich z bazy. Dobra, co jeszcze ciekawego... Już chyba wystarczy, jest 1:30 w nocy, skończyłem chyba siódmą kawę dzisiaj a wypalonych fajek nie liczy nikt :) 7. Funkcja include() a konflikt izraelsko palestyński Mają one z sobą niewiele wspólnego. A skoro poruszyliśmy już temat include(), może trochę go rozwiniemy. Funkcje include(), require() czy require_once() wykorzystywane są do włączania do skryptów plików zawierających gotowe funkcje, znaczniki HTML, klasy itd. Bardzo często włączane pliki zawierają hasła dostępu do bazy danych czy inne ważne informacje i nie jest wskazane wydostanie się tych informacji na zewnątrz. Złota zasada dołączanych plików mówi, że nie powinno być możliwości aby te pliki przesyłane były do przeglądarki jako czysty tekst. Pierwszym sposobem jest nadanie tym plikom rozszerzenia.php wówczas interpretowane one będą przez PHP przy każdym wysłaniu i niewiele da się wtedy z nich odczytać. Ten sposób nie jest zalecany i wykorzystywany jest przy dołączaniu prostych plików nie zawierających ważnych informacji. My zajmiemy się sposobem zalecanym pliki dołączane trzymane są poza drzewem strony www. W ten sposób nie można się do nich dostać przez bezpośrednie odwołanie w przeglądarce. Przyjęło się także, że dołączane pliki posiadają rozszerzenie.inc. Pierwszym krokiem powinno więc być wyłączenie w Apaczu przesyłanie jakichkolwiek plików z rozszerzeniem.inc. Bierzemy się więc za httpd.conf i dopisujemy: 10
<Files ~ "\.inc$"> Order allow,deny Deny from all </Files> Między \ a inc w pierwszej linii jest kropka :) Mamy więc dwa poziomy zabezpieczeń: (1) pliki.inc leżą poza drzewem serwera www a sam Apacz i tak nie może ich wysłać (2). Pozostało jeszcze tak zamieszać, żeby skrypty PHP mogły dostać się do plików.inc. Służy do tego zmienna include_path w pliku php.ini. Załóżmy, że Zdzichu jest webmasterem firmy, której udostępniamy serwer wirtualny. Nich katalogiem głównym strony www wspomnianej firmy będzie /home/zdzichu/firma_pl/. Pliki dołączane Zdzisiek chciałby trzymać w /home/zdzichu/firma_inc/. Mamy teraz dwa wyjścia. Lepsze zmiana w odpowiednim miejscu httpd.conf: php_value include_path /home/zdzichu/firma_inc Po przeładowaniu Apacza każdy plik umieszczony przez Zdzicha w firma_inc można przy pomocy include( plik.inc ) dołączać go do skryptów. PHP sprawdzi wówczas /home/zdzichu/firma_inc/ i jeśli odnajdzie tam plik.inc dołączy go do skryptu. Jak się już pewnie domyślasz, drugim sposobem jest ustawienie dla danego katalogu w httpd.conf opcji AllowOverride Options i wówczas Zdzichu przy pomocy.htaccess będzie sam sobie mógł w analogiczny sposób zdefiniować include_path. A przy okazji wiele innych flag i dlatego jest to ten gorszy sposób... 8. Ukryjmy, co się da Jak już pewnie zauważyłeś, gdy coś spartolisz w skrypcie, na stronę wysyłany jest komunikat z odpowiednim błędem. Jest to rozwiązanie pozwalające na zlokalizowanie błędu w krótkim czasie. I bardzo dobrze. Gdy jednak przetestowałeś już swoją stronkę dobrze by było gdybyś wyłączył wyświetlanie błędów na stronie. Jeśli coś pójdzie nie tak, któryś element się wyłoży, na stronę mogą trafić takie rzeczy jak lokalizacja skryptów, loginy, fragment kodu to nie jest dobre, może zdradzić zbyt wiele informacji. Poza tym osoba która ogląda Twoją stronę jest bardziej zainteresowana tym, że nic z tego nie będzie a nie tym w jaki sposób to do niej dotrze. W którym miejscu umieścić plik z logami PHP? Ja trzymam logi Apacza (access_log, error_log) w /var/log/apache/, dlatego php_log powędruje właśnie tam. Ważna uwaga: plik ten powinien mieć prawa zapisu dla użytkownika z którego prawami chodzi serwer www (tutaj: www). Tworzymy sobie wyżej wymieniony plik: touch /var/log/apache/php_log chown www:www /var/log/php_log A następnie dopisujemy / poprawiamy w php.ini: 11
error_reporting = E_ALL; display_errors = Off; log_errors = On; error_log = /var/log/apache/php_log; Nazwy opcji mówią same za siebie. Oczywiście jeśli pracujesz nad jakąś nową stroną lub takową testujesz użyj flag i włącz wywalanie błędów dla określonego miejsca. Lub zrób odwrotnie domyślnie włącz wyświetlanie a przy pomocy flag dla dobrych stron je wyłącz. A właściwie po co ktoś ma wiedzieć, że używasz PHP na serwerze? Naklejki w stylu Powered by PHP to coś jak naklejka Adidas na samochodzie dresiarza. Spróbujmy więc trochę zabunkrować fakt, że używasz PHP. Plik httpd.conf: ServerSignature Off Plik php.ini: expose_php = Off; Nic nam takie zabiegi, jeśli w adresie strony po chamsku widać rozszerzenie.php w nazwach plików. Dlatego też możemy je zmienić, na przykład na.asp lub.dhtml lub.kma (to ostatnie to kiss my ass). Nie jest dobrym pomysłem zmiana na.html, ponieważ wówczas zwykłe, czyste HTMLowe pliki będą parsowane niepotrzebnie co zaowocuje niepotrzebnym obciążeniem serwera. Jeśli przy okazji wyłączymy wyświetlanie błędów na stronie, mamy wtedy zagwarantowaną chociaż odrobinę prywatności :) Plik httpd.conf: AddType application/x-httpd-php.dhtml No i tyle. Musisz tylko pamiętać, żeby zamiast.php nadawać rozszerzenia.dhtml. W przeciwnym razie źródełka popłyną do przeglądarek... 12
9. Inne Poniższego nie miałem gdzie umieścić dlatego powstał ten punkt. Opcją, którą powinieneś wyłączyć w php.ini jest allow_url_fopen. Funkcja ta wykorzystywana jest w szczątkowej ilości serwerów a umożliwia otwieranie plików, np. przy pomocy include() czy fopen(), ze zdalnych serwerów poprzez http czy ftp. Mało praktyczne natomiast stosunkowo niebezpieczne. Pisząc skrypty PHP gdzieś w drzewie serwera www, nie nazywaj kolejnych kopii zapasowych skryptu w stylu.php.bak czy.php.old. Są one łatwo dostępne z przeglądarki i już wiesz co dalej. Najlepiej przenieś je poza drzewko serwera www. Hmm... Nic więcej nie przychodzi mi do głowy. Mam nadzieję, że dzięki powyższemu bezpieczeństwo Twojego serwerka poprawi się chociaż o trochę. Jeśli znajdziesz jakiś błąd lub wiesz o czymś, co powinno się znaleźć w tym dokumencie napisz do mnie. Jest to pierwsza wersja tego dokumentu i zawiera pewnie jakieś błędy / niedoróbki / potknięcia itp. Będę bardzo wdzięczny za wszelkie uwagi, komentarze, poprawki, wyrazy wdzięczności. Z góry przepraszam za powyższe i mam nadzieję, że będziecie mnie informować w których miejscach coś nie gra. Jako (częściowe) wytłumaczenie przedstawiam fakt, że większość tej pracy powstawała w późnych godzinach nocnych. Kontakt ze mną: linio@terramail.pl -------------------------------------- Henryk Liniowski http://linio.terramail.pl Poznań, 2003 -------------------------------------- 13