Polska Strona Freesco

Lekki i szybki, ale nie słaby

Serwery z systemem NND pracują na różnym sprzęcie. Czasem niezbyt wydajnym. Jeśli trzeba na takim słabym sprzęcie uruchomić serwer www, to okazuje się, że wspólpraca z apache odbija się czkawką. Wbudowany w NND thttpd ma zaś mizerne możliwości. Jest jednak alternatywa – lighttpd (http://www.lighttpd.net). Poniżej dokładny artykuł Andrzeja na ten temat.

Serwer Apache jest bardzo popularnym i solidnym serwerem WWW. Nie dziwi więc powszechne używanie jego modułów do obsługi Perla, PHP czy Pythona. Przywiązanie do mod_php, czy mod_python wiąże nas na dobre i złe z tym serwerem. Większe pole manewru daje nam korzystanie z FastCGI. Nie dość, że zyskujemy większą uniwersalność, objawiającą się możliwością wyboru odpowiadającego nam serwera WWW z całej gamy dostępnych programów, to jeszcze niektóre frameworki (Aranha czy Ruby on Rails) „odwdzięczą” nam się lepszą pracą i mniejszym zużyciem pamięci. Inną kwestią jest stabilność. Ponieważ moduły Apache’a są związane z rdzeniem serwera poważny błąd w skryptach przez nie obsługiwanych może odbić się bardzo niebezpiecznie na stabilności całego serwera. Procesy FastCGI są izolowane od serwera. Jak któryś się zawiesi, to serwerowi nic się nie stanie. Proces można ubić, zrestartować. Daje to znacznie większą stabilność pracy serwera. Ostatnią, ale bardzo istotną kwestią jest bezpieczeństwo. Każdy skrypt odpalany w trybie mod_php, mod_python czy mod_perl na Apache’u jest odpalany w kontekście tego samego uzytkownika. Tworzy to dosyć poważną dziurę bezpieczeństwa na serwerach hostingowych. Każdy użytkownik na serwerze za pomocą prostego kodu PHP może przeglądać źródła dowolnego pliku innych użytkowników. Wszyscy mają dostęp do wszystkich! W FastCGI tego problemu nie ma. Kod skryptu można uruchomić na prawach użytkownika a nie serwera WWW, dzięki czemu można pracować w pełnej izolacji. Dlaczego w takim razie nie stosuje się FastCGI w Apache’u ?
Odpowiedź jest prosta – moduł FastCGI do Apache’a ma opinię nie do końca stabilnego i dopracowanego. 🙂
Jest to pierwszy powód, dla którego zwróciłem uwagę na serwer Lighttpd, który od samego początku kładł nacisk na dobrą implementację swego modułu FastCGI. Jest on stabilniejszy i lepiej dopracowany niż pod Apache.
Innymi zaletami Lighttpd jest szybkość, niewielkie zasoby zajmowane na dysku i dość spore możliwości. Ten serwer WWW obsłuży nam nie tylko statyczne strony w HTML, ale również dość skomplikowane portale napisane w PHP czy Ruby z użyciem baz danych mysql. Mając taki portal nie unikniemy obciążenia systemu przez mysql i php, ale nie dodamy do zajętych zasobów dość wymagającego serwera Apache.
Wstępne porównania przeprowadzone przez Maćka na komputerze P350 ze 128 MB RAM pokazały korzyści. Proces lighttpd ani razu nie znalazł się na czele listy top i strony były serwowane wyraźnie sprawniej. Na szybszych komputerach też jest widoczna różnica w serwowaniu dynamicznie generowanej zawartości. I tak na Celeronie 1,7 GHz (Wilamette) i 512 MB pamięci różnica szybkości działania systemu akwizycji danych napisanego w PHP pod Lighttpd w porównaniu do mod_php pod Apachem przewyższa 50%.
Także od strony administracyjnej Lighttpd ma kilka zalet, a przede wszystkim łatwą konfigurację. Jeden plik konfiguracyjny lighttpd.conf znajdujący się domyślnie w katalogu /etc/lighttpd/. Do poprawnej pracy w pliku konfiguracyjnym wystarczą wpisy:

server.document-root = „/var/www/”

server.port = 80

mimetype.assign = (
„.html” => „text/html”,
„.txt” => „text/plain”,
„.jpg” => „image/jpeg”,
„.png” => „image/png”
)

static-file.exclude-extensions = ( „.rb”, „.pl”, „.fcgi”, „.php”, „~”, „.inc” )

server.indexfiles = ( „index.htm”, „index.html”, „index.rb”)
ssi.extension = ( „shtml” )
server.modules = ( „mod_cgi”, „mod_ssi” )

cgi.assign = ( „.pl” => „/usr/bin/perl”,
„.sh” => „”,
„.cgi” => „/usr/bin/perl” )

Przy prawidłowym uruchomieniu taki wychudzony konfig pozwoli nam mieć serwer HTTP pracujący na zadanym porcie, z obsługą CGI oraz mechanizmu Server Side Includes. Plik konfiguracyjny znajdujący się w pakiecie do NND jest znacznie bardziej skomplikowany. Większość opcji jest poprzedzona znakiem „#”, a co za tym idzie nieaktywna. Na stronie http://trac.lighttpd.net/trac/wiki/Docs%3AConfigurationOptions dostępny jest szczegółowy opis konfiguracji parametrów samego programu jak i modułów. Na początku ustawiamy w zmiennej server.document-root ścieżkę do katalogu, z którego Lighttpd domyslnie pobiera wszystkie obsługiwane przez siebie dokumenty. Zmienna server.port deklaruje port, na którym będzie pracował serwer a zmienne server.username i server.groupname definiują odpowiednio użytkownika i grupę, na którego prawach będzie uruchomiony serwer. Warto jest także ustawić zmienną server.errorlog, która wskazuje na pełną ścieżkę do pliku logu błędów. Ktoś, kto poradził sobie z konfiguracją Apache’a nie powinien mieć problemu z Lighttpd. Zapewne niektórzy pamiętają opcje ServerTokens i ServerSignature Apache’a, dzięki którym Apacz nie przedstawia się w sposób ułatwiający szukanie eksploita. W Lighttpd mamy o niebo lepiej – w zmiennej server.tag możemy sobie wpisać dowolny string identyfikujący serwer albo ciąg pusty aby wyłączyć identyfikację. Możemy wpisać np.: „Apache/2.2.3 (Unix) DAV/2 mod_ssl/2.2.3 OpenSSL/0.9.8b PHP/5.1.6 Server at xxx.pl Port 80” (żywcem zerżnięte z pierwszego lepszego serwera WWW działającego na NND) albo „Microsoft-IIS/5.0” i niech się domorosłe hakiery dziwią dlaczego eksploit nie zadziałał 🙂
W zmiennej server.modules znajdziemy dość długi łańcuch modułów, które mogą być uruchomione. Moduły te zapewniają możliwość uzyskania praktycznie wszystkich funkcji, które znamy z popularnego apacza (np. vhosty, czy katalogi użytkowników). Modułów używaj z głową, jest pewne, że nie potrzebujesz ich wszystkich do szczęścia. Zwróć uwagę, że każdy moduł spowalnia w pewnym stopniu serwer i zwiększa zapotrzebowanie na pamięć. Niektóre moduły pokrywają się częściowo funkcjonalnie (np.: mod_simple_vhost i mod_mysql_vhost) i ich włączenie prowadzi do dziwnych efektów. Dla przykładu jednoczesne włączenie mod_compress i mod_deflate skutecznie pomoże nam pozbyć się wyświetlania stron indeksu.
Moduły, których nie ma na liście w pliku konfiguracyjnym nie występują w tej wersji Lighttpd lub też nie są z nią kompatybilne.
Większość modułów takich jak: mod_accesslog (tworzy konfigurowalne wpisy historii żądań HTTP w pliku dziennika serwera), mod_auth (autentyfikacja użytkownika), mod_compress (wysyłanie strony w postaci skompresowanej), mod_evasive (ograniczenie liczby połączeń), mod_rewrite (mapowanie adresów URL) czy mod_usertrack (śledzenie użytkownika) ma swoje bezpośrednie odpowiedniki w Apache’u. Istnieją także moduły, których tam nie znajdziecie: mod_deflate (wysyłanie dynamicznie generowanej zawartości w postaci skompresowanej), mod_secdownload (zaawansowana blokada hotlinkingu), mod_magnet (sterowanie przetwarzaniem zapytań) czy mod_uploadprogress (śledzenie postępu uploadu pliku).
W przeważającej części przypadków do określania wzorców możemy używać wyrażeń regularnych, np. w mod_redirect:

url.redirect = ( „^/get/([0-9]+)/([0-9]+)$” => „http://www.example.org/get.php?isdn=$1&page$2” )

Taki wpis spowoduje, że wejście na stronę http://<adres_serwera>/get/21/4 spowoduje przekierowanie na adres http://www.example.org/get.php?isdn=21&page4
Natomiast w module mod_dirlisting za pomocą wyrażeń regularnych w zmiennej dir-listing.exclude możemy ustalić kryteria obiektów, które będą pomijane przy wyświetlaniu zawartości katalogów. W tym samym module, podobnie jak w Apache’u możemy wyświetlić przy zawartości katalogu nagłówek i stopkę zawierającą, np.: komentarz odnośnie zawartości katalogów. W tym celu przygotowujemy dwa pliki tekstowe nazwane HEADER.txt i README.txt (proszę zwrócić uwagę na małe i duże litery) zawierające tekst nagłówka i stopki. Pliki kopiujemy do katalogu udostępnionego przez WWW a do pliku konfiguracyjnego dodajemy opcje:

dir-listing.encoding = „iso-8859-2”
dir-listing.show-readme = „enable”
dir-listing.hide-readme-file = „enable”
dir-listing.show-header = „enable”
dir-listing.hide-header-file = „enable”

Niewątpliwie ciekawym dodatkiem jest wsparcie Ligttpd dla rrd, co w łatwiejszy sposób pomoże w uzyskaniu ciekawych statystyk rysowanych przez rrd.
Jeśli będziemy chcieli korzystać z połączeń szyfrowanych SSL, nie powinno to także sprawić kłopotu. W pliku konfiguracyjnym umieszczamy odpowiednie wpisy włączające połączenia szyfrowane i ustawiające parametry:

$SERVER[„socket”] == „twoja.domena.pl:443” {
ssl.engine = „enable”
ssl.pemfile = „/etc/lighttpd/server.pem”
#ssl.ca-file = „/etc/lighttpd/CA_issuing.crt”
#server.name = „twoja.domena.pl”
#server.document-root = „/home/httpd/https”
#server.errorlog = „/var/log/lighttpd/serror.log”
#accesslog.filename = „/var/log/lighttpd/saccess.log”
}

W zasadzie wystarczy ustawienie dwóch lub trzech zmiennych, reszta (zahashowana) przyda się gdy będziemy chcieli ustawić inną zawartość strony niż przy połączeniach HTTP, czy też utworzyć oddzielne pliki logu odnoszące się tylko do połączeń szyfrowanych. W przypadku kiedy wykupiliśmy odpowiedni certyfikat do zabezpieczenia serwerów WWW w urzędzie certyfikującym, musimy wskazać do niego pełną ścieżkę w zmiennej ssl.ca-file. Jeżeli nie mamy takiego certyfikatu SSL musimy go sobie wygenerować i podpisać sami.
Odbywa się to w nieco inny sposób niż dla serwera Apache – prościej i bez utrudnień typu usuwanie hasła:
openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes
Plik server.pem kopiujemy w upatrzone miejsce (np.: do /etc/lighttpd/) i nadajemy mu odpowiednie prawa:
chown nobody:nogroup /etc/lighttpd/server.pem && chmod 0600 /etc/lighttpd/server.pem

Lighttpd dobrze sprawuje się zarówno w małych serwisach internetowych, jak i portalach. W przypadku tych drugich stosowane są wbudowane w niego mechanizmy rozkładające obciążenie na kilka lub kilkanaście maszyn (load-balancing). Przy mocno obciążonych serwisach przyda się także możliwość ograniczania transferu. Lighttpd obsługuje globalne ograniczanie szybkości każdego połączenia do określonej wartości, ale także nakładanie niezależnych limitów prędkości na poszczególne dokumenty.
Czas na współpracę z PHP. Ponieważ PHP z repozytorium przygotowane jest tak, że nadaje się tylko do Apache’a, na nic się nam nie przyda. Mamy dwie możliwości: kompilujemy wszystko sami lub korzystamy z gotowego pakietu przygotowanego przez Maćka (http://nnd-linux-router.one.pl/pkg/). Przy samodzielnej kompilacji z parametrów skryptu configure usuwamy –with-apxs2 i dodajemy na końcu parametry –enable-fastcgi –enable-discard-path –enable-force-redirect. Gdy mamy już PHP nie spsute pod jeden jedyny serwer WWW, w pliku php.ini dodajemy wpis cgi.fix_pathinfo = 1. Kolejnym krokiem jest edycja pliku konfiguracyjnego serwera /etc/lighttpd/lighttpd.conf, odnajdujemy i usuwamy hashe sprzed modułów:
mod_proxy_core
mod_proxy_backend_http
mod_proxy_backend_fastcgi
a następnie np.: na końcu pliku konfiguracyjnego dodajemy wpis:

$HTTP[„url”] =~ „.php$” {
proxy-core.balancer = „round-robin”
proxy-core.allow-x-sendfile = „enable”
proxy-core.check-local = „enable”
proxy-core.protocol = „fastcgi”
proxy-core.backends = ( „unix:/tmp/php-fastcgi.sock” )
proxy-core.max-pool-size = 16
}

Po zainstalowaniu Lighttpd z przygotowanego pakietu nie ma konieczności przeprowadzania żadnych zmian w jego konfiguracji, aby działała integracja z PHP. Powyższe informacje podaje na wypadek jakby ktoś przy ekperymentowaniu z konfiguracją zepsuł współpracę z PHP. Całość możemy przetestować wykonując polecenie:
echo '<?php phpinfo(); ?>’ > /var/www/phpinfo.php
a następnie wpisując w przeglądarce adres http://ip_serwera/phpinfo.php – powinna nam się wyświetlić strona z informacjami na temat PHP.
Lighttpd posiada możliwość generowania informacji o stanie webserwera takich jak uptime, aktywne połączenia i ich stan, ilość przesłanych danych, szybkość transferu, używane moduły, wkompilowane rozszerzenia, czy zestawy liczników używanych do śledzenia stanu FastCGI lub innych protokołów. Żeby mieć dostep do tych statystyk wystarczy odhashować mod_status i ustawić zawartość zmiennych status.status-url, status.config-url i status.statistics-url. Ponieważ informacje zawarte w statystykach nie powinny trafić do każdego, powinniśmy w jakiś sposób ograniczyć dostęp do nich osobom z zewnątrz. Najprościej zrobić do dodając do pliku konfiguracyjnego wpis:

$HTTP[„remoteip”] == „192.168.0.0/24” {
status.status-url = „/server-status”
status.config-url = „/server-config”
status.statistics-url = „/server-statistics”
}

Oznacza on, że zmienne status.status-url, status.config-url i status.statistics-url zostaną ustawione (a tym samym zostaną włączone statystyki) tylko gdy IP komputera łączącego się z serwerem zawiera się z zakresie od 192.168.0.1 do 192.168.0.254. Podane ścieżki nie mają reprezentować określonych plików czy katalogów a co za tym idzie nie istnieją w systemie plików. Nawet gdy w /var/www/ mamy tylko jeden plik index.html i żadnych innych plików czy katalogów, a w pliku konfiguracujnym Lighttpd umieścimy wpis status.status-url = „/nobodyliveshere” to po wpisaniu w przeglądarce http://adres_serwera/nobodyliveshere otrzymamy stronę podobną jak ta http://orion.isx.pl/server-status.htm . Przy większej liczbie połączeń możemy je sortować wg. zadanych kryteriów klikając na wybranej komórce nagłówka tabeli, np.: „State:”.
Przy okazji otrzymaliśmy prosty przykład konfiguracji warunkowej, która to jest bardzo potężnym narzędziem. Oprócz pola $HTTP[„remoteip”], oznaczającego adres hosta zdalnego, możemy użyć dopasowań sprawdzających:
$HTTP[„cookie”] – cookie
$HTTP[„host”] – hosta
$HTTP[„useragent”] – nagłówek identyfikujący program, który połączył się z naszym serwerem
$HTTP[„referer”] – nagłówek referer, pozwalający sprawdzić z jakiej strony ktoś wszedł na naszą stronę
$HTTP[„url”] – adres URL
$SERVER[„socket”] – socket w formacie „ip:port”
Oprócz ostatniego dopasowania możemy użyć różnych operatorów porównania zadanego stringa czy wyrażenia regularnego Perla np:.

# zabroń dostępu do swojego serwera <cośtam>.example.org wszystkim złodziejom obrazków

$HTTP[„referer”] !~ „^(.*.)?example.org$” {
url.access-deny = ( „.jpg”, „.jpeg”, „.gif”, „.png” )
}

Po szczegóły odsyłam do dokumentacji Lighttpd.
A skoro jesteśmy już przy metodach zabezpieczania stron przed niepożądanym dostępem pewnie zainteresuje nas poniższy wpis do konfiguracji ilustrujący możliwość łączenia warunków:

$HTTP[„host”] == „www.example.org” {
$HTTP[„remoteip”] !~ „195.117.23.38|192.168.0.2” {
$HTTP[„url”] =~ „^/admin/” {
url.access-deny = ( „” )
}
}
}

W ten sposób zabezpieczyliśmy stronę http://www.example.org/admin/ tak aby mieć do niej dostęp z komputera w domu i w pracy. Wpis należy tłumaczyć w ten sposób: jeżeli łączysz się z serwerem www.example.org a twoje IP jest inne niż 195.117.23.38 i inne niż 192.168.0.2 i próbujesz się dostać do zawartości ścieżki admin to zostaniesz zablokowany.
No dobrze, ale przecież, gdy ktokolwiek z twojej pracy będzie próbował wejść na tą stronę ze swojego komputera to także uzyska dostęp. Apache miał możliwość zabezpieczania wybranych katalogów hasłem za pomocą pliku .htaccess. Nie próbuj robić W Lighttpd kontroli dostępu do zasobów za pomocą tej metody. It doesn’t work.
Żeby było trudniej załóżmy, że chcemy udostępnić statystyki serwera tylko adresom IP z sieci lokalnej – z zewnątrz mają być niewidoczne. Nie chcemy, aby użytkownicy naszej sieci mieli dostęp do takich strategicznych danych bo im też może przyjąć ochota na psoty. Niestety czasami jesteśmy u usera, który zgłasza np.: dziwne zachowanie sieci i od niego chcemy mieć dostęp do statystyk. Zrobimy więc tak aby z twojego komputera (192.168.0.2) był nieograniczony dostęp do statystyk a z komputerów userów uzyskamy dostęp dopiero po podaniu użytkownika i hasła.
Na początku tworzymy plik .htpasswd, jego struktura jest identyczna jak w Apache’u co z pewnością ucieszy zakochanych w programie The Apache Software Foundation. Zamiast kombinować ręcznie, wykorzystajmy narzędzie htpasswd:

htpasswd -c /etc/lighttpd/user.htpasswd admin
Adding password for admin
New password: <wpisujemy hasło>
Re-type new password: <wpisujemy to samo hasło jeszcze raz>

Następnie analogicznie dodamy kolejnego użytkownika poleceniem:
htpasswd /etc/lighttpd/user.htpasswd user

Utworzony plik .htpasswd ma postać:
admin:hlia.D4ebSZAw
user:sqLQtkpRyERMI

W pliku konfiguracyjnym lighttpd.conf dodajemy wpis:

$HTTP[„remoteip”] == „192.168.0.0/24” {
status.status-url = „/server-status”
status.config-url = „/server-config”
status.statistics-url = „/server-statistics”
$HTTP[„remoteip”] != „192.168.0.2/32” {
auth.backend = „htpasswd”
auth.backend.htpasswd.userfile = „/etc/lighttpd/user.htpasswd”
auth.require = ( „/server-config” =>
(
„method” => „basic”,
„realm” => „Statystyki serwera”,
„require” => „valid-user”
), „/server-status” =>
(
„method” => „basic”,
„realm” => „Statystyki serwera”,
„require” => „valid-user”
), „/server-statistics” =>
(
„method” => „basic”,
„realm” => „Statystyki serwera”,
„require” => „valid-user”
))
}
}

Możemy zadeklarować globalnie jeden plik user.htpasswd, albo do każdego zabezpieczanego katalogu przypisać zupełnie inny plik z hasłami. Nazwa user.htpasswd jest tylko przykładowa, nie musimy trzymać jakiegoś szablonu.
Gdy mamy jeden globalny plik z hasłami i kilka zasobów zabezpieczonych przy jego wykorzystaniu (tak jak w przykładzie ze statystykami), po autoryzowaniu się przy jednej statystyce uzyskuje dostęp do reszty statystyk już bez wpisywania hasła. Niektóre przeglądarki przechowują uwierzytelnione sesje do czasu zamknięcia całej przeglądarki (a nie tylko karty z daną stroną). Jeśli miałbym np.: phpMyAdmina zabezpieczonego w taki sposób i z pośpiechu nie zamknąłbym przeglądarki, na której wcześniej zalogowałem się do statystyk, użytkownik tego komputera uzyskałby dostęp do phpMyAdmina. Problem jest natury ogólnej i dotyczy także innych serwerów WWW takich jak Apache, czy thttpd. Rozwiązań jest kilka. Najprostsze to w pliku user.htpasswd utworzyć kilku użytkowników i zamienić opcje w konfigu „require” => „valid-user” np.: na „require” => „user=user” w przypadku statystyk i na „require” => „user=admin” w przypadku phpMyAdmina. Gdy będziemy próbowali zalogować się na siłę do phpMyAdmina za pomocą loginu „user” i prawidłowego hasła przeglądarka zwróci nam bład „400 – Bad Request”. Lepszym rozwiązaniem jest stworzenie oddzielnego pliku z hasłami do każdego zabezpieczonego zasobu. W Lighttpd można ten problem rozwiązać jeszcze inaczej, a przy okazji załatwić kolejny problem bezpieczeństwa. Od kilku lat zmieniłem chyba ze 4 sieci osiedlowe. Jedne obejmowały dziesiątki, inne nawet setki komputerów, ale cechą wspólną wszystkich sieci był brak zabezpieczeń przed sniffowaniem. Kiedyś admin jednej z tych sieci zapytany o kwestię zabezpieczeń przed podsłuchem (udałem przestraszonego klienta) powiedział, że oni używają switchów więc problemu nie ma. A skoro problemu nie ma to nie pochwaliłem się mu że przez pół dnia pracy sniffera w moje łapy wpada kilkanaście haseł poczty, czasem jakieś hasła do ftpów. Podsłuchiwać można także transmisję HTTP; szyfrowanie transmisji za pomocą SSL znacznie utrudnia sprawę, jednakże czasem zdarzają się sytuacje kiedy nie możemy wykorzystać SSL. Jak to wygląda w praktyce ?! Załóżmy, że w przeglądarce wpisałem adres http://192.168.0.1/server-status i pojawił mi się monit o podanie użytkownika i hasła. Statystyki zabezpieczyliśmy wg. ostatniego przykładu. Wpisujemy login i hasło i uzyskujemy dostęp do strony ze statystykami. W tym samym czasie sniffer uruchomiony na innym komputerze w sieci wypisał:
Host: 192.168.0.1
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: pl,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-2,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cache-Control: max-age=0, max-age=0
Authorization: Basic dXNlcjpTZWNyZXQ=

Hmmm, w polu „Authorization” mamy „zaszyfrowane” hasło. Problem w tym, że jest ono zakodowane tylko za pomocą Base64 i wystarczy użyć odpowiedniego programu lub wejść na jedną z setek stron z dekoderami online, skopiować „dXNlcjpTZWNyZXQ=” do schowka i wkleić ją np.: na http://www.opinionatedgeek.com/dotnet/tools/Base64Decode/ potem wciskamy „Decode” i mamy wszystko jak na dłoni.
Apache posiada specjalny moduł mod_auth_digest, który implementuje uwierzytelnienie HTTP Digest. Moduł nie został jednak dobrze przetestowany i jest oznaczony jako eksperymentalny. W Lighttpd nie ma nawet takiego eksperymentalnego modułu. Nie znaczy to, że Lighttpd nie obsługuje uwierzytelnienia HTTP Digest – nie dość, że obsługuje to jego uzyskanie jest bardzo proste. Zabezpieczmy w ten sposób katalog phpMyAdmina. Na początek musimy usunąć phpMyAdmina z wpisów auth.require o ile taki wpis zrobiliśmy podczas eksperymentów z plikiem konfiguracyjnym. W konfiguracji Lighttpd wstawiamy sekcję:

$HTTP[„url”] =~ „^/phpMyAdmin/” {
auth.backend = „htdigest”
auth.backend.htdigest.userfile = „/etc/lighttpd/user.htdigest”
auth.require = („/phpMyAdmin” => (
„method” => „digest”,
„realm” => „Wymagana autoryzacja”,
„require” => „valid-user”
))
}

Następnie tworzymy plik z hasłami:
echo -n 'user:realm_z_przykładu_wyżej:’ > /etc/lighttpd/user.htdigest
echo 'user:realm_z_przykładu_wyżej:hasło’ | md5sum | cut -b -32 >> /etc/lighttpd/user.htdigest

Przykładowa poprawna zawartość pliku user.htdigest:
master:Wymagana autoryzacja:ce7d499772512198344a1370a36f04f6

Eee, to już wszystko. Wystarczy tylko przeładować serwer, żeby przyjął zmiany w konfiguracji. Czas na testy, otwieramy przeglądarkę i wpisujemy adres http://192.168.0.1/phpMyAdmin/ , pojawił się monit o wprowadzenie nazwy użytkownika i hasła, zupełnie jak przy poprzedniej metodzie. Wpisujemy login i hasło i uzyskujemy dostęp do strony phpMyAdmina. W tym samym czasie sniffer uruchomiony na innym komputerze w sieci wypisał:
Host: 192.168.0.1
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.8.1.3) Gecko/20070309 Firefox/2.0.0.3
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: pl,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-2,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Cookie: pma_fontsize=100%25; pma_theme=original; pma_lang=pl-utf-8; pmaCookieVer=4; pma_charset=iso-8859-2; pma_collation_connection=cp1250_general_ci; phpMyAdmin=a5c538360d2eb3c3d64511d0696d5503
Authorization: Digest username=”master”, realm=”Wymagana autoryzacja”, nonce=”c683f7897c1d09b80192285cc1a80fba”, uri=”/phpMyAdmin/”, response=”11ba3e4f297c8765ad461946a2e0e19c”, qop=auth, nc=00000001, cnonce=”51b9b094e570e4ea”
Cache-Control: max-age=0, max-age=0

OK, usera mamy jak na dłoni, ale hasło?! Hasło jest zaszyfrowane i wysyłane jako hash z użyciem mechanizmu Challenge/Response. Nie zaleca się używania tej metody do zabezpieczania hasłem stron dostępnych od zewnątrz… zresztą ryzyko podsłuchu w sieci wewnętrznej jest wielokrotnie większe.

Możliwe jest uzyskanie efektu, dzięki któremu każda spisana ścieżka w URL będzie prawidłowa, wystarczy wpisać w pliku konfiguracyjnym server.error-handler-404 = „/index.html” a gdy użytkownik spróbuje połączyć się ze stroną, która nie istnieje, zostanie wyświetlona strona znajdująca się w pliku /var/www/index.html. Jeśli wszystkie zawarte w niej odnośniki podane są jako bezwzględne uzyskamy efekt przekierowania na stronę początkową, a przeglądarka dostanie w odpowiedzi kod 200 oznaczający, że dokument istnieje. Jeśli nie podobają się nam domyślne strony błędów, możemy podmienić je na własne za pomocą zmiennej server.errorfile-prefix.
Warto poświęcić trochę czasu na konfigurację programu, a zyskamy sprawny i bardzo szybki serwer www.

Andrzej Boreczko (Orion)


Dodaj komentarz