background image

 

 

 

 

 

 

 

 

Referat  

Temat: Apache i skrypty PHP 

Wykonali: 

Zbigniew Kiliański 
Paweł Ścipień 
Artur Zając 

Prowadzący zajęcia: 

mgr inż. Bogusław Juza 

Data: 

28-05-2002 

Rok studiów: 

IV 

Rok akademicki: 

2001/2002 

 

 

background image

 

Spis tresci: 

 

1.

 

Wstęp

.................................................................................................................................................................. 3

 

2.

 

Metody uruchomienia programu napisanego w PHP

........................................................................................... 4

 

2.1.

 

Obsługa PHP  w kompilowana w Apache statycznie,

.................................................................................. 4

 

2.2.

 

Moduł PHP ładowany dynamicznie do Apache,

......................................................................................... 5

 

2.3.

 

Skrypty PHP uruchamiane jako tzw. skrypty CGI,

...................................................................................... 7

 

2.4.

 

Skrypty PHP uruchamiane z wykorzystaniem biblioteki "fastcgi",

............................................................. 9

 

3.

 

Tryb safe mode

.................................................................................................................................................. 10

 

4.

 

Analiza kodu suexec

.......................................................................................................................................... 12

 

5.

 

Pomysły na rozbudowanie kodu suexec

............................................................................................................ 21

 

5.1.

 

Modyfikacja suexec tak, aby uruchamiać pliki PHP z uprawnieniami właściciela pliku:

......................... 21

 

5.2.

 

4.2   Obsługa limitów setrlimit().

............................................................................................................... 22

 

6.

 

Wnioski

............................................................................................................................................................. 28

 

7.

 

Literatura

........................................................................................................................................................... 29

 

background image

 

 

1. Wstęp 

 

PHP  jest  szeroko  stosowanym  językiem,  który  służy  do  tworzenia  witryn  z  dynamicznie, 

zmieniającymi się stronami WWW. Język ten umożliwia generowanie stron po stronie serwera i 

przekazywanie  efektów  działania  programów  w  postaci  kodu  HTML  interpretowanego    przez 

przeglądarki  po  stronie  klienta.  Swoją  popularność  język  ten  zawdzięcza  swojej  prostocie, 

bogatym  zbiorze  funkcji  operujących  na  danych,  dużym  możliwością  podłączenia  się  z  bazami 

danych i doskonalej dokumentacji dostępnej na firmowej stronie WWW. 

Strony  WWW  udostępniane  są  przez  demona  HTTPD  działającego  na  serwerze. 

Najpopularniejszym  demonem  świadczącym  tego  typu  usługi  jest  demon  Apache  dostępny  na 

stronie (www.apache.org). Demon ten odpowiedzialny jest za udostępnianie stron klientom, oraz 

za uruchamianie skryptów generujących te strony. 

Ze  wzglądów  bezpieczeństwa  serwer  Apache  nie  jest  uruchamiany  z  uprawnieniami 

administratora systemu. Użytkownik, z którego uprawnieniami działa serwer Apache zwykle nie 

posiada własnych plików i nie ma możliwości zapisu do plików, które nie są "zapisywalne" przez 

każdego  użytkownika.  Taka  konfiguracja  systemu  poprawia  znacznie  bezpieczeństwo  aplikacji 

działających  na  serwerze,  ponieważ  nawet  złamanie  demona  nie  daje  możliwości  zapisu  lub 

odczytu  plików  na  serwerze,    które  maja  zabezpieczony  dostęp  dla  użytkowników  innych  niż 

właściciel główny lub grupowy. 

Czasami jednak istnieje konieczność uruchomienia skryptów, które posiadają uprawnienia 

większe  lub  inne  niż  użytkownik,  który  jest  właścicielem  procesów  Apache'a,  ponieważ  należy 

np.  zabezpieczyć  dostęp  do  odczytu  niektórych  plików  np.  z  hasłami  do  bazy  danych.  Problem 

ten rozwiązuje tzw. wrapper o nazwie suexec. Plik programu suexec ma ustawiony bit suid dla 

właściciela  pliku  i  właścicielem  pliku  jest  administrator  systemu.  Uruchomienie  skryptów 

wymagających  specjalnych  uprawnień  polega  na  wywołaniu  wrappera  suexec  przez  proces 

Apache, a następnie uruchomieniu przez wrappera właściwego skryptu. Dostęp do plików innych 

użytkowników  może  być  także  zabezpieczony  przez  wykorzystanie  trybu  „safe  mode”  i 

właściwej konfiguracji serwera. 

Istnieje kilka sposobów uruchamiania skryptów PHP. Każdy ze sposobów ma swoje zalety 

i  wady,  z  którymi  trzeba  się  pogodzić  i  w  zależności  od  potrzeby  należy  wybrać  odpowiednią 

background image

 

metodę  uruchamiania  skryptów.  Analiza  problemów  związanych  z  uruchomieniem  skryptów 

PHP zajmuje się ten referat. 

 

2. Metody uruchomienia programu napisanego w PHP 

 Istnieje wiele sposobów uruchamiania skryptów PHP. Każdy z nich umożliwia uzyskanie 

pewnych  właściwości,  zazwyczaj  kosztem  innych.  Najważniejszymi  metodami  uruchamiania 

skryptów PHP są: 

 

2.1.   Obsługa PHP  w kompilowana w Apache statycznie, 

 

Obsługę PHP można włączyć do kodów serwera Apache podczas kompilacji serwera (jest 

to  tzw.  kompilacja  statyczna).  Zaleta  takiej  konfiguracji  jest  względnie  bardzo  duża    szybkość 

działania  skryptów  PHP.  Serwer  taki  konfiguruje  się  w  ten  sposób,  ze  najpierw  kompiluje  się 

PHP włączając informacje o ścieżce do kodów źródłowych Apache'a, a następnie kompiluje się 

Apache'a.  

Kompilacja statyczna Apache i PHP 

$ gunzip -c apache_1.3.x.tar.gz | tar xf - 

$ cd apache_1.3.x 

$ ./configure 

$ cd .. 

 

$ gunzip -c php-4.2.x.tar.gz | tar xf - 

$ cd php-4.2.x 

$ ./configure --with-mysql --with-apache=../apache_1.3.x \ 

--enable-track-vars 

$ make 

$ make install 

 

$ cd ../apache_1.3.x 

$ ./configure --prefix=/www --activate-module=  

  src/modules/php4/libphp4.a 

$ make 

$ cd ../php-4.2.x 

background image

 

$ cp php.ini-dist /usr/local/lib/php.ini

 

 

Konfiguracja php polega na edycji pliku /usr/local/lib/php.ini. 

Następnie należy powiązać rozszerzenie pliku ze skryptem (np. .php) z interpreterem oraz 

(opcjonalnie) rozszerzenie pliku (np. .phps) z interpreterem, który koloruje i wyświetla kod PHP 

w  przeglądarce.  W  tym  celu  należy  zmodyfikować  plik  konfiguracyjny  Apache  httpd.conf  lub 

srm.conf i dodać:   

AddType application/x-httpd-php .php 

AddType application/x-httpd-php-source .phps 

 

W  wyniku  kompilacji  Apache'a tworzony zostaje serwer, który posiada "zaszytą" w sobie 

obsługę  PHP.  Korzystając  z  tej  metody  można  uzyskać  najszybsza  z  możliwych  obsługę 

skryptów PHP.  Szybkość ta wynika z tego, że podczas wykonywania skryptów PHP nie trzeba 

doładowywać  bibliotek  dynamicznych,  ani  tworzyć  procesów,  które  uruchamiają  się  długo  w 

stosunku do całkowitego czasu działania skryptów. 

Wadą  tej  metody  jest  bardzo  mała  elastyczność  konfiguracji.  Chcąc  zmienić  wersje 

interpretera PHP musimy przekompilować cały serwer Apache. Wada także jest fakt, ze skrypty 

PHP uruchamiane tą drogą muszą dziedziczyć uprawnienia procesu, który je wywołuje, a w tym 

wypadku musi to być Apache. Nie ma więc możliwości zmiany uprawnień skryptów. 

Ograniczenie  to  można  ominąć  uruchamiając  oddzielny  serwer  Apache  na  innym  porcie 

przez  innego  użytkownika  i  przekierowując  niektóre  zapytania  na  ten  serwer  (wykorzystując 

dyrektywę  Redirect). 

 

2.2.   Moduł PHP ładowany dynamicznie do Apache, 

Druga  prezentowana  metoda  jest  kompilacja  obsługi  PHP  jako  moduł  dynamicznie 

ładowany  podczas  uruchamiania  skryptów  PHP.  Najpierw  kompiluje  się  serwer  Apache, 

włączając  opcje  obsługi  dynamicznie  ładowanych  modułów.  W  tym  celu  podczas 

konfigurowania źródeł Apache'a należy dodać do polecenia ./configure opcje  

--enable_module=so

Następnie  należy  dokonać  kompilacji  modułu  PHP  z  wykorzystaniem  programu  apxs, 

który  umożliwia  automatyczną  konfiguracje  modułu  w  zależności  od  wykorzystywanej 

konfiguracji Apache (np. opcja -DEAPI, gdy korzystamy z modułu modssl). 

background image

 

Jeżeli  mamy  już  zainstalowany  serwer  Apache  wraz  z  obsługa  dynamicznych  modułów 

PHP kompiluje się w nastepujący sposób: 

$ gunzip -c php-4.2.x.tar.gz | tar xf - 

$ cd php-4.2.x 

$ ./configure --with-mysql --with-apxs 

$ make 

$ make install 

 

Po skompilowaniu modułu PHP program instalacyjny umieszcza go w stosownym miejscu 

(tj. w katalogu libexec/  pod nazwą libphp4.so).  

Nast

ępnie należy skopiować i z edytować plik php.ini 

$ cd ../php-4.2.x 

$ cp php.ini-dist /usr/local/lib/php.ini 

 

Następnie należy zmodyfikować plik httpd.conf.  

Modyfikacja  pliku  httpd.conf  polega  na  umieszczeniu  dyrektyw  ładujących  moduł 

PHP  do  Apacha  oraz  umieszczeniu  dyrektyw  informujących  serwer,  ze  pliki  o  zadanym 

rozszerzeniu powinny być interpretowane przez PHP. 

Wiązanie  plików  z  rozszerzeniem  .php    i  .phps  (rozszerzenia  mogą  być  dowolne)  z 

interpreterem: 

AddType application/x-httpd-php .php 

AddType application/x-httpd-php-source .phps 

Ładowanie  modułu  PHP  do  serwera  Apache  (wiersze  te  powinny  być  automatycznie 

dodane, przez apxs). 

LoadModule php4_module libexec/libphp4.so 

AddModule mod_php4.c 

 

W  przeciwieństwie  do  poprzedniego  rozwiązania,  to  daje  możliwość  zmiany  ustawień 

modułu  PHP  (np.  dodanie  obsługi  GD)  bez  konieczności  ponownej  kompilacji  kodów  serwera 

Apache.  Zaleta  ta  rekompensuje  bardzo  niewielką  (około  5%)  utratę  szybkości  interpretacji 

skryptów.  Poważną  wadą  rozwiązania  jest  brak  możliwości  uruchamiania  skryptów  z 

uprawnieniami  właściciela,  ponieważ  skrypty  PHP  są  uruchamiane  przez  użytkownika,  z 

uprawnieniami serwera Apache. 

background image

 

Wadę tą da się ominąć uruchamiając serwer Apache na innym porcie przez odpowiedniego 

użytkownika (podobnie jak miało to miejsce w poprzednio opisanej metodzie). 

 

 

 

2.3.   Skrypty PHP uruchamiane jako tzw. skrypty CGI, 

 

Jedna  z  najczęściej  używanych  metod  uruchamiania  skryptów  po  stronie  serwera  jest 

metoda  zwana  CGI.  CGI  jest  specyfikacja  interfejsu  wymiany  informacji  pomiędzy  aplikacją 

serwera  np.  Apache,  a  programem/  skryptem  napisanym  przez  użytkownika,  którego  głównym 

(najczęstszym)  zadaniem  jest  wygenerowanie  strony  HTML,  która  jest  następnie  przekazywana 

użytkownikowi.  Jedynym  wymaganiem  stawianym  przez  specyfikację  CGI  odnośnie  języków 

programowania jest to, ze program napisany w stosownym języku musi umieć odczytać dane ze 

standardowego  wejścia  i  musi  umieć  zapisywać  dane  na  standardowym  wyjściu.  Ponieważ 

praktycznie wszystkie języki spełniają te wymagania, istnieje możliwość napisania skryptów CGI 

w dowolnym języku.  

Główną  wada  skryptów  CGI  jest  czas  inicjacji  programu  i  obciążenie  systemu  tym 

spowodowane.  Skrypt  CGI,  który  jest  uruchamiany  przez  program  wymaga  utworzenia  tzw. 

ciężkiego  procesu.  Narzut  czasowy  związany  z  tą  czynnością  jest  niejednokrotnie  większy  niż 

całkowity  czas  pracy  skryptu,  dlatego  rozwiązanie  to  nie  jest  rozwiązaniem  optymalnym  w 

przypadku skryptów PHP. 

Czasem  istnieje  jednak  konieczność  uruchamiania  skryptów  PHP  jako  procesy  CGI. 

Najważniejsza  zaleta  tego rozwiązania jest możliwość uruchamiania  skryptów z uprawnieniami 

właściciela przy wykorzystaniu programu suexec.  

Kompilacja  kodów  źródłowych  PHP  jest  prostsza  niż  w  przypadku  wersji  statycznie 

wkompilowanej  w  kody  Apacha  i  wersji  dynamicznie  ładowanego  modułu,  ponieważ 

standardowo PHP kompiluje się jako interpreter, który powinien być uruchamiany jako CGI.  

Kompilacje  PHP  jako  interpreter  CGI  i  'uruchamiany  z  shella'  przeprowadza  się 

następująco: 

1) ./configure (parametry dołączanych bibliotek do PHP) 

2) make 

3) make install 

background image

 

W  wyniku  tych  komend  zostanie  utworzony  plik  php,  który  jest  interpreterem  skryptów 

PHP.  Następnie  kopiuje  się  go  do  katalogu,  który  się  znajduje  np.  w  zmiennej  PATH  lub 

katalogu, który przechowuje skrypty CGI (np. jeden z aliasów /cgi-bin/). 

 

Istnieje  także  wiele  sposobów  skonfigurowania  serwera  Apache,  tak  aby  uruchamiał 

skrypty PHP jako CGI. 

Najprostszym  z  nich  jest  nazywanie  skryptów  z  użyciem  rozszerzenia  .cgi  lub  innego 

wyspecyfikowanego przez następujacą dyrektywę w httpd.conf; 

AddHandler cgi-script .cgi

 

Zawartość  plików  uruchamianych  w  ten  sposób  powinna  wyglądać  na  przykład 

następująco: 

 

#!/usr/local/bin/php 

<? phpinfo(); ?>

 

 

Wadą  tego  rozwiązania  jest  konieczność  umieszczania  ścieżki  w  pierwszym  wierszu 

skryptu.  Jest  to  pewnym  kłopotem,  jeśli  chcemy  zmienić  uprawnienia  napisanych  już  skryptów 

ponieważ  zmuszeni  jesteśmy  wtedy  do  modyfikacji  każdego  skryptu.  W  jednym  z  następnych 

punktów opisano modyfikację programu suexec, która omija tą wadę.  

 

Pewnym rozwiązaniem jest dodanie nowego handlera do rozszerzenia pliku i powiązania z 

nim akcji: 

 

AddHandler php-script php 

Action php-script /cgi-bin/php 

 

Niestety  sposób  ten,  nie  jest  obsługiwany  przez  suexec.  Wiec  bez  modyfikacji  kodów 

programu suexec i Apache nie jest uruchomienie skryptów z uprawnieniami właściciela ( w ten 

sposób). 

Istnieje możliwość zmiany właściciela wykonywanych skryptów na wirtualnych domenach. 

Konfiguracja tego sposobu zmiany użytkownika polega na zadeklarowaniu użytkownika i grupy 

(który jest właścicielem skryptów). 

<VirtualHost 192.168.1.1:80> 

background image

 

ServerName www.test.com.pl 

DocumentRoot /www/testcom 

ErrorLog /www/log/testcom_error 

TransferLog /www/log/testcom_transfer 

User usrtest 

Group grptest 

</VirtualHost> 

 

 

2.4.   Skrypty PHP uruchamiane z wykorzystaniem biblioteki "fastcgi", 

FastCGI jest biblioteka i modułem, który umożliwia przyspieszenie uruchamiania skryptów 

CGI  na  serwerze.  Więc  przy  użyciu  FastCGI  można  częściowo  rozwiązać  problem  z  dużym 

narzutem związanym z nakładem mocy obliczeniowej przeznaczonej na tworzenie procesu. 

Przyspieszenie  osiągnięte  dzięki  FastCgi  wynika  z  tego, że  moduł  ten  wczytuje  z  dysku  i 

inicjuje skrypty raz i przetrzymuje je w pamięci. Dzięki temu nie ma potrzeby tworzenia nowego 

procesu  dla  każdego  zapytania  oddzielnie.  Minimalizuje  to  w  znaczący  sposób  obciążenie 

komputera i przyspiesza czas reakcji na zapytanie. 

Konfiguracja  PHP  różni  się  od  wersji  CGI    jedynie  opcja  dodawana  podczas 

konfigurowania  źródeł  PHP.  (moduł  i  biblioteka  FastCgi  powinna  być  już  wcześniej 

zainstalowana). 

./configure --with-fastcgi 

 

FastCGI jako moduł jest włączany do Apacha poprzez stosowne dyrektywy w httpd.conf. 

LoadModule fastcgi_module     libexec/mod_fastcgi.so 

AddModule mod_fastcgi.c 

 

Obsługę  PHP  jako  FastCGI  konfiguruje  się  wewnątrz  pliku  httpd.conf  poprzez  dodanie 

dyrektyw: 

 

Alias /fcgi-bin/ /www/fcgi-bin/ 

FastCgiSuexec /www/bin/suexec 

AddType application/x-httpd-fcgi .fcgi 

AppClass /www/htdocs/fcgi-bin/php.fcgi -processes 4 

AddType application/x-httpd-fphp .fhtml  

background image

10 

 

Action application/x-httpd-fphp /www/htdocs/fcgi-bin/php.fcgi

 

 

Taka  konfiguracja  powoduje,  ze  skrypty  są  uruchamiane  o  wiele  szybciej  niż  przez  CGI. 

Niestety  skrypty  są  jednak  uruchamiane  wolniej  niż  przy  pomocy  modułu  wkompilowanego  w 

Apache lub modułu  dynamicznie dołączanego do Apache. Wadą rozwiązania jest także fakt, ze 

podczas  normalnej  pracy  serwera  uruchomionych  jest  wiele  interpreterów  php  (wersji  dla  fast-

cgi), które niekoniecznie są w danej chwili potrzebne. Powodują one jednak to, ze przy obsłudze 

zapytania nie ma konieczności natychmiastowego uruchamiania (ładowania, tworzenia procesu) 

interpretera i przez to obciążenie systemu jest mniejsze i czas reakcji szybszy. 

 

3. Tryb safe mode 

W przypadku administrowania serwerem z wieloma użytkownikami, którym nie można w 

pełni  zaufać  istnieje  konieczność  ograniczenia  pewnych  możliwości  jakie  daje  korzystanie  z 

PHP.  Najważniejszymi  potencjalnie  niebezpiecznymi  możliwościami  są  udostępnianie  plików 

leżących  poza  drzewem  Apache’a    na  stronach  WWW,  uruchamianie    programów  (niezależnie 

od  tego  gdzie  leżą),  zmiana  zmiennych  środowiskowych,  korzystanie  z  potencjalnie 

niebezpiecznych funkcji. 

Aby  ograniczyć  niektóre  prawa  użytkownika  korzystającego  z  PHP  administrator  może 

wykorzystać  tryb  safe  mode  uruchamiania  skryptów  PHP.  Tryb  ten  włączany  jest  przy  pomocy 

dyrektywy safe_mode  w pliku konfiguracyjnym php.ini lub w pliku httpd.conf. 

Przykład php.ini: 

 

safe_mode = On

 

 

Przykład httpd.conf: 

 

php_flag safe_mode on 

 

Włączenie  trybu  safe  mode  powoduje  zmodyfikowanie  działania  niektórych  funkcji.  W 

większości są to funkcje wejścia/wyjścia. Modyfikacja ich polega w większości na tym, że przed 

wykorzystaniem  ich  właściwej  opcji  np.  na  pliku  sprawdzane  jest  czy   plik należy do tej samej 

osoby  co  właściciel.  W  przypadku  funkcji  uruchamiających  inne  skrypty  lub  programy 

sprawdzane jest czy znajdują się one we właściwym miejscu. 

Na działanie skryptu PHP w trybie safe mode wpływają następujące dyrektywy: 

 

background image

11 

 

safe_mode

 

Dyrektywa  ta  włącza  lub wyłącza  tryb safe mode oraz wpływ innych dyrektyw trybu safe 

mode na działanie programu. 

 
safe_mode_gid

 

Podczas operacji plikowych sprawdzane jest czy właściciel pliku, na którym wykonywana 

jest operacja jest taki sam jak właściciel skryptu. W przypadku niezgodności właściciela pliku i 

skryptów wykonanie operacji zostaje zabronione. 

 Jeżeli dyrektywa safe_mode_gid jest włączona w przypadku niezgodności właścicieli 

pliku  i  skryptów  sprawdzane  jest  także  czy  właściciel  grupowy  pliku  i  skryptów  są  takie  same. 

Jeżeli właściciel grupowy jest ten sam to operacja wejścia/wyjścia jest wykonywana. 

 
open_basedir

 

Dyrektywa,  ta  specyfikuje  katalogi,  z  których  użytkownikowi  wolno  otwierać  pliki.  Przy 

pomocy  tej  dyrektywy  możemy  ograniczyć  użytkownikowi  prawa  do  otwierania  plików  poza 

wybranym drzewem katalogów. 

 
safe_mode_include_dir

 

Dyrektywa  ta  specyfikuje  katalogi  (wraz  z  ich  podkatalogami),  z  których  użytkownikowi 

wolno  includować  pliki,  które  nie  są  jego  własnością.  Pliki  includowane  położone  poza  tym 

drzewem muszą mieć tego samego właściciela co uruchamiany skrypt . 

 
safe_mode_exec_dir 

Dyrektywa  ta  specyfikuje  katalogi  (wraz  z  ich  podkatalogami),  z  których  użytkownikowi 

wolno uruchamiać zewnętrzne programy  np. przy użyciu funkcji system. 

 
 
safe_mode_allowed_env_vars

 

Przy  pomocy  tej  dyrektywy  możemy  wyszczególnić  prefixy  zmiennych  środowiskowych, 

które mogą być zmieniane przez użytkownika wykorzystującego funkcję putenv(). Można podać 

więcej prefixów oddzielając je przecinkami. 

 
safe_mode_protected_env_vars

 

Przy pomocy tej dyrektywy można podać listę zmiennych środowiskowych, które nie mogą 

być  modyfikowane  przez  użytkownika  funkcją  putenv().  Zmienne  takie  nie  będą  mogły  być 

modyfikowane nawet jeżeli objęte zostały dyrektywą safe_mode_allowed_env_vars. 

 

 

disable_functions 

 

background image

12 

 

Ta  dyrektywa  umożliwia  podanie  nam  listy  funkcji,  które  zostają  zablokowane  i 

użytkownik  nie  może  z  nich  skorzystać.  Nazwy  funkcji  są  oddzielone  przecinkami. Nie  można 

korzystać z tej dyrektywy wyłącznie wewnątrz pliku php.ini. 

 

Większość  dyrektyw  tych  można  definiować  także  wewnątrz  pliku  httpd.conf  (w 

konfiguracji  Apache’a)  .  Daje  nam  to  możliwość  zmiany  właściwości  trybu  safe  mode  dla 

poszczególnych wirtualnych domen, a także dla poszczególnych katalogów.  

 

Przykład takiej definicji w pliku httpd.conf wygląda następująco: 

php_flag safe_mode on 
 
<Directory /docroot> 
  php_admin_value open_basedir /docroot  
</Directory>

 

 

 

 

 

4. Analiza kodu suexec 

Poniżej zamieszczono dokładny opis kodu programu suexec, który służy jako pośrednik do 

uruchamiania skryptów CGI. 

 

Deklaracja  bezpiecznych  zmiennych  środowiskowych,  które  mogą  zostać  przekazane 

skryptowi uruchamianemu, przy pomocy suexec. 

char *safe_env_lst[] = 

    "AUTH_TYPE", 

    "CONTENT_LENGTH", 

    "CONTENT_TYPE", 

    "DATE_GMT", 

    "DATE_LOCAL", 

    "DOCUMENT_NAME", 

    "DOCUMENT_PATH_INFO", 

    "DOCUMENT_ROOT", 

    "DOCUMENT_URI", 

    "FILEPATH_INFO", 

background image

13 

 

    "GATEWAY_INTERFACE", 

    "LAST_MODIFIED", 

    "PATH_INFO", 

    "PATH_TRANSLATED", 

    "QUERY_STRING", 

    "QUERY_STRING_UNESCAPED", 

    "REMOTE_ADDR", 

    "REMOTE_HOST", 

    "REMOTE_IDENT", 

    "REMOTE_PORT", 

    "REMOTE_USER", 

    "REDIRECT_QUERY_STRING", 

    "REDIRECT_STATUS", 

    "REDIRECT_URL", 

    "REQUEST_METHOD", 

    "REQUEST_URI", 

    "SCRIPT_FILENAME", 

    "SCRIPT_NAME", 

    "SCRIPT_URI", 

    "SCRIPT_URL", 

    "SERVER_ADMIN", 

    "SERVER_NAME", 

    "SERVER_ADDR", 

    "SERVER_PORT", 

    "SERVER_PROTOCOL", 

    "SERVER_SOFTWARE", 

    "UNIQUE_ID", 

    "USER_NAME", 

    "TZ", 

    NULL 

}; 

 

Funkcja  wyprowadzająca  komunikaty  diagnostyczne  do  pliku  logów.  Plik  ten  jest 

zdefiniowany 

podczas 

kompilacji 

Apacha 

przez 

ustawienie 

--suexec-

logfile=NAZWAPLIKU

static void err_output(const char *fmt, va_list ap)

 

background image

14 

 

 

Funkcja  przetwarzająca  zmienną  liczbę  argumentów    i  wywołująca  funkcje 

err_output()

 w celu wypisania komunikatu do plików logów. 

static void log_err(const char *fmt,...) 

 

Funkcja  oczyszcza  środowisko  ze  zmiennych,  niebezpiecznych.  Za  zmienne  bezpieczne 

uznawane są tylko zmienne, których nazwy zostały umieszczone w tablicy safe_env_lst[] 

oraz zmienne zaczynające się prefiksem HTTP_. Maksymalna ilość zmiennych jest umieszczona 

w stałej AP_ENVBUF zdefiniowanej na początku pliku. 

 

 

 

Funkcja main(int argc, char *argv[]) uruchamia polecenie ze zmienionymi uprawnieniami. 

Działanie funkcji: 

Sprawdza czy użytkownik, który wywołuje program istnieje w pliku /etc/passwd 

    uid = getuid(); 

    if ((pw = getpwuid(uid)) == NULL) { 

 

log_err("crit: invalid uid: (%ld)\n", uid); 

 

exit(102); 

    } 

 

Sprawdza  czy  można  wyświetlić  info.  Info  jest  wyświetlane  wtedy  jeżeli:  liczba 

argumentów  jest  większa  niż  1,  parametr  przekazany  do  funkcji  jest  równy  "-V"  oraz  osoba 

wywołującą  program  jest  root  lub  użytkownik  HTTPD_USER  (czyli  użytkownik,  z 

uprawnieniami którego działa Apache i uprawniony jest do uruchamiania programu suexec). Po 

wyświetleniu informacji program jest zatrzymywany. 

 

Jeżeli  liczba  parametrów  jest  mniejsza  od  4,  program  jest  kończony  z  błędem  i 

komunikatem do logów. 

if (argc < 4) { 

 

log_err("alert: too few arguments\n"); 

 

exit(101); 

 

background image

15 

 

Następnie  pobierana  jest  z  argumentów  wejściowych  nazwa  użytkownika,  grupy    i 

programu uruchamianego przez tego użytkownika. 

target_uname = argv[1]; 

target_gname = argv[2]; 

cmd = argv[3]; 

 

Sprawdza  czy  użytkownik,  który  próbuje  uruchomić  program  ma  do  tego  uprawnienia. 

Użytkownik,  który  wywołuje  program  definiowany  jest  w  trakcie  kompilacji  lub  w  pliku 

suexec.h

if (strcmp(HTTPD_USER, pw->pw_name)) { 

 log_err("crit: calling user mismatch (%s instead of %s)\n", 

 

 

pw->pw_name, HTTPD_USER); 

 

exit(103); 

 

Sprawdza  czy  łańcuch  komendy  wykonywanej  zaczyna  się  "/"  lub  "../"  lub  zawiera  "/../'. 

Zabezpieczenie  to  ma  na  celu  wyeliminowanie  możliwości  uruchamiania  programu  z  korzenia 

systemu plików lub "cofania" się w hierarchii systemu plików. 

 

if ((cmd[0] == '/') || (!strncmp(cmd, "../", 3)) 

 

|| (strstr(cmd, "/../") != NULL)) { 

        log_err("error: invalid command (%s)\n", cmd); 

 

exit(104); 

    } 

 

Sprawdza  czy  suexec  ma  do  czynienia  z  wywołaniem  programu  z  konta  użytkownika. 

Jeżeli tak to usuwa z nazwy użytkownika pierwszy znak tj. "~" (tyldê). 

if (!strncmp("~", target_uname, 1)) { 

 

target_uname++; 

 

userdir = 1; 

 

Sprawdza czy docelowy użytkownik istnieje w systemie. 

if ((pw = getpwnam(target_uname)) == NULL) { 

background image

16 

 

 

log_err("crit: invalid target user name: (%s)\n", 

target_uname); 

 

exit(105); 

 

Sprawdza poprawność grupy docelowej (numeru, ewentualnie nazwy). 

if (strspn(target_gname, "1234567890") != strlen(target_gname)) 

  if ((gr = getgrnam(target_gname)) == NULL) { 

   log_err("crit: invalid target group name: (%s)\n", 

target_gname); 

    exit(106); 

  } 

  gid = gr->gr_gid; 

  actual_gname = strdup(gr->gr_name); 

else { 

 

gid = atoi(target_gname); 

 

actual_gname = strdup(target_gname); 

 

Zapisanie  id  użytkownika,  nazwy  użytkownika  i  docelowego  katalogu  w  zmiennych 

pomocniczych. 

uid = pw->pw_uid; 

actual_uname = strdup(pw->pw_name); 

target_homedir = strdup(pw->pw_dir); 

 

Otwarcie pliku logów i zalogowanie o zaistniałym zdarzeniu: 

log_err("info: (target/actual) uid: (%s/%s) gid: (%s/%s) cmd: 

%s\n", 

 

    target_uname, actual_uname, 

 

    target_gname, actual_gname, 

 

    cmd); 

 

background image

17 

 

Sprawdzenie czy użytkownik docelowy nie jest rootem i czy jego uid nie jest mniejszy od 

zmiennej  UID_MIN,  która  jest  ustawiana  w  pliku  suexec.h  lub  w  trakcie  konfigurowania 

Apache'a. 

 

if ((uid == 0) || (uid < UID_MIN)) { 

log_err("crit: cannot run as forbidden uid (%d/%s)\n",     

uid, cmd); 

 

exit(107); 

 

To samo dla grupy docelowej. 

if ((gid == 0) || (gid < GID_MIN)) { 

log_err("crit: cannot run as forbidden gid (%d/%s)\n", gid, 

cmd); 

 

exit(108); 

 

Zmienia uprawnienia procesu na uprawnienia użytkownika docelowego. Najpierw setgid(), 

a pózniej setuid(). 

if (((setgid(gid)) != 0) || (initgroups(actual_uname, gid) != 

0)) { 

 

log_err("emerg: failed to setgid (%ld: %s)\n", gid, cmd); 

 

exit(109); 

 

if ((setuid(uid)) != 0) { 

 

log_err("emerg: failed to setuid (%ld: %s)\n", uid, cmd); 

 

exit(110); 

 

Pobranie nazwy aktualnego katalogu. 

if (getcwd(cwd, AP_MAXPATH) == NULL) { 

 

log_err("emerg: cannot get current working directory\n"); 

 

exit(111); 

background image

18 

 

 

Sprawdzenie czy osiągalny jest docelowy katalog roboczy dla programu uruchamianego.  

Dla  programu  uruchamianego  w  normalnym  trybie  sprawdzana  jest  także  czy  katalog 

docelowy  jest  w  poddrzewie  katalogu  zawartego  w  stałej  DOC_ROOT  ustawianej  podczas 

konfiguracji lub w pliku suexec.h. 

if (userdir) { 

 

if (((chdir(target_homedir)) != 0) || 

 

    ((chdir(USERDIR_SUFFIX)) != 0) || 

 

    ((getcwd(dwd, AP_MAXPATH)) == NULL) || 

 

    ((chdir(cwd)) != 0)) { 

log_err("emerg: cannot get docroot information 

(%s)\n",target_homedir); 

 

    exit(112); 

 

    } 

    else { 

 

if (((chdir(DOC_ROOT)) != 0) || 

 

    ((getcwd(dwd, AP_MAXPATH)) == NULL) || 

 

    ((chdir(cwd)) != 0)) { 

    log_err("emerg: cannot get docroot information (%s)\n", 

DOC_ROOT); 

 

    exit(113); 

 

    } 

 

    if ((strncmp(cwd, dwd, strlen(dwd))) != 0) { 

log_err("error: command not in docroot (%s/%s)\n", cwd, 

cmd); 

 

exit(114); 

    } 

 

Pobranie  informacji  o  katalogu  aktualnym,  w  którym  będzie  uruchamiany  program 

docelowy. 

if (((lstat(cwd, &dir_info)) != 0) || 

!(S_ISDIR(dir_info.st_mode))) { 

background image

19 

 

 

log_err("error: cannot stat directory: (%s)\n", cwd); 

 

exit(115); 

    } 

 

Sprawdzenie  czy  katalog  może  być  zapisywany  przez  innych  użytkowników  lub 

użytkowników w tej samej grupie (jeśli tak to błąd). 

if ((dir_info.st_mode & S_IWOTH) || (dir_info.st_mode & 

S_IWGRP)) { 

log_err("error: directory is writable by others: (%s)\n", 

cwd); 

 

exit(116); 

 

Pobranie informacji o programie. 

if (((lstat(cmd, &prg_info)) != 0) || 

(S_ISLNK(prg_info.st_mode))) { 

 

log_err("error: cannot stat program: (%s)\n", cmd); 

 

exit(117); 

 

Sprawdza czy program uruchamiany, może być zapisywany przez innych (jeśli tak to błąd). 

if ((prg_info.st_mode & S_IWOTH) || (prg_info.st_mode & 

S_IWGRP)) { 

 

log_err("error: file is writable by others: (%s/%s)\n", cwd, 

cmd); 

 

exit(118); 

    } 

 

Błąd jeżeli program ma ustawiony bit SGID lub SUID. 

if ((prg_info.st_mode & S_ISUID) || (prg_info.st_mode & 

S_ISGID)) { 

 log_err("error: file is either setuid or setgid: (%s/%s)\n", 

cwd, cmd); 

 exit(119); 

background image

20 

 

 

Sprawdza  czy  docelowa  grupa  i  użytkownik  są  właścicielami  programu  uruchamianego  i 

katalogu, w którym ten program jest uruchamiany. 

if ((uid != dir_info.st_uid) || 

 

(gid != dir_info.st_gid) || 

 

(uid != prg_info.st_uid) || 

 

(gid != prg_info.st_gid)) { 

 

log_err("error: target uid/gid (%ld/%ld) mismatch " 

 

 

"with directory (%ld/%ld) or program (%ld/%ld)\n", 

 

 

uid, gid, 

 

 

dir_info.st_uid, dir_info.st_gid, 

 

 

prg_info.st_uid, prg_info.st_gid); 

 

exit(120); 

 

Sprawdza, czy program jest uruchamialny przez właściciela 

if (!(prg_info.st_mode & S_IXUSR)) { 

 log_err("error: file has no execute permission: (%s/%s)\n", 

cwd, cmd); 

 exit(121); 

 

Sprawdza  poprawne  ustawienie  maski  dla  tworzonych  plików  tak,  aby  pliki  utworzone 

przez wywoływany program nie mogły byś zapisywane przez innych użytkowników systemu. 

if ((~SUEXEC_UMASK) & 0022) { 

 

log_err("notice: SUEXEC_UMASK of %03o allows " 

"write permission to group and/or other\n", 

SUEXEC_UMASK); 

    } 

    umask(SUEXEC_UMASK); 

 

Czyści zmienne środowiskowe uruchamianego programu. 

clean_env(); 

 

Zamyka plik logów. 

background image

21 

 

if (log != NULL) { 

 

fclose(log); 

 

log = NULL; 

 

Uruchomienie programu. 

#ifdef NEED_HASHBANG_EMUL 

  /* We need the #! emulation when we want to execute scripts */ 

  { 

 

extern char **environ; 

 

ap_execve(cmd, &argv[3], environ); 

  } 

#else /*NEED_HASHBANG_EMUL*/ 

    execv(cmd, &argv[3]); 

#endif /*NEED_HASHBANG_EMUL*/ 

 

Zapisanie informacji do logów w przypadku nieprawid

łowego 

uruchomienia skryptu. 

 

log_err("emerg: (%d)%s: exec failed (%s)\n", errno, 

strerror(errno), cmd); 

exit(255); 

 

 

 

5. Pomysły na rozbudowanie kodu suexec 

5.1.  Modyfikacja suexec tak, aby uruchamiać pliki PHP z uprawnieniami 

właściciela pliku: 

Z jednym ze wcześniejszych punktów zasygnalizowano możliwość uruchamiania skryptów  

z  wykorzystaniem  suexec. Celem modyfikacji jest umożliwienie uruchamiania plików PHP bez 

konieczności  wpisywania w pierwszym wierszu każdego skryptu ścieżki do interpretera PHP tak 

aby uruchamiały się one z uprawnieniami właściciela pliku. 

Modyfikacja ta polega na rozpoznawaniu po rozszerzeniu czy jest to plik PHP (oraz wersji) 

oraz uruchomieniu odpowiedniego interpretera skryptów. 

background image

22 

 

Najważniejsza modyfikacja źródeł suexe.c  jest następująca: 

   if (czy_php(cmd))  

        if ((newargv[0] = getPhpInterpreter(cmd)) == NULL) { 

 

        fprintf(stderr, "interpreter nie znaleziony\n"); 

 

        exit(130); 

        } 

    newargv[1] = cmd; 

    newargv[2] = NULL; 

 

Powyższy  kod  sprawdza  na  postawie  rozszerzenia  czy  polecenie  jest  plikiem  PHP.  W 

zależności  od  tego  czy  plik  ma  rozszerzenie  .php,  .php3  lub  .php4.  dobiera  odpowiedni 

interpreter.  Oraz  buduje  tablice  zawierającą  parametry  do  uruchomienia  interpretera  wraz    z 

odpowiednim skryptem. 

 Tablica  newargv[]  przekazywana  jest  następnie  do  funkcji  ap_execve(),  która  odpowiedzialna 

jest za uruchomienia skryptu. 

 

5.2.  4.2   Obsługa limitów setrlimit(). 

Obecnie 

serwer 

Apache 

nie 

udostępnia 

możliwości 

ograniczenia 

zasobów 

wykorzystywanych przez programy CGI. Zasoby te mogą być ograniczone poprzez standardowe 

ustawienia  w  systemie,  które  są  stosowane  dla  każdego  programu.  Ograniczenia  te  można 

zmieniać  wykorzystując  polecenie  ulimit/limit  (w  zależności  od  shella).  Administrator  nie  ma 

jednak możliwości ograniczenia w ten sposób tylko do skryptów CGI i dlatego potrzebne wydaje 

się  zmodyfikowanie  serwera  tak,  aby  mógł  wpływać  na  ograniczenia  w  przydzielaniu  zasobów 

systemowych.  Aby  zrealizować  ten  cel  można  zmodyfikować  kod  programu  suexec,  który  jest 

odpowiedzialny  za  uruchamianie  skryptów  CGI.    Modyfikacja  programu  będzie  polegać  na 

odczytaniu  pliku  konfiguracyjnego,  zinterpretowaniu  jego  zawartości  i  ustawieniu  limitów  dla 

niego samego, a takze dla wszystkich innych programów, które suexec uruchomi.  

Ponieważ  w  naszym  rozwiązaniu  korzystamy  z  funkcji  systemowej  setrlimit()  dlatego 

mamy możliwość nadania programowi następujących ograniczeń. 

 
RLIMIT_CPU  - czas procesora 
RLIMIT_FSIZE – maksymalny rozmiar pliku

 

RLIMIT_DATA  - maksymalny rozmiar segmentu danych 
RLIMIT_STACK  - maksymalny rozmiar segmentu stosu 
RLIMIT_CORE – maksymalny rozmiar pliku core (tworzonego gdy w skrypcie 

wyst

ąpi błąd) 

RLIMIT_RSS     maksymalna wielko

ść pamięci rezydentnej 

background image

23 

 

RLIMIT_NPROC  - maksymalna ilo

ść towrzonych procesów 

RLIMIT_NOFILE – maksymalna ilo

ść otworzonych plików 

RLIMIT_MEMLOCK – maksymalna wielkoœæ obszaru locked-in-memory  

 

Ponieważ jest to zadanie modelowe plik konfiguracyjny ma postać możliwie najprostsza.  

Dane  są  w  pliku  oddzielone  przecinkami  i  znajdują  się  w  jednym  wierszu.  Wartość  ujemna 

oznacza brak limitu. 

Kolejne wartości w pliku oznaczają: 

RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_DATA, RLIMIT_STACK, RLIMIT_CORE, RLIMIT_RSS, 
RLIMIT_NPROC, RLIMIT_NOFILE,RLIMIT_MEMLOCK  

 

Przykład: 

5,1223423,-1,1324214,2224313,14242223,12234233,13242234,-1 

 

Modyfikacja  kodów  programu  suexec  sprowadza  się  do  dodania  dwóch  dyrektyw  define 

oznaczających  ścieżkę  do  pliku  konfiguracyjnego  i  maksymalny  jego  rozmiar  (który  powinien 

być  niewielki  z  powodu  niewielu  informacji  w  nim  trzymanych),  funkcji  odczytującej  plik  i 

interpretującej  jego  zawartość  oraz  kilka  wierszy  sprawdzających  uprawnienia  do  pliku 

konfiguracyjnego i ustawiających limity. Ponadto trzeba „zaincludować” stosowne pliki. 

 

Wiersze  definiujące  maksymalny  rozmiar  pliku  konfiguracyjnego  oraz  ścieżkę  do  tego 

pliku: 

#define MAXCONFBUF 1000 

#define MAXCONFPATH "/etc/param.conf" 

 

Funkcja odczytująca i interpretująca zawartość pliku konfiguracyjnego. W przypadku błędu 

funkcja ta zwraca –1 i wypisuje komunikat do pliku logów. 

 

 

int odczytaj_limit(char *nazwa_pliku,struct rlimit *rl_CPU, struct rlimit 

*rl_FSIZE,struct rlimit *rl_DATA,struct rlimit *rl_STACK,struct rlimit 

*rl_CORE,struct rlimit *rl_RSS,struct rlimit *rl_NPROC,struct rlimit 

*rl_NOFILE,struct rlimit *rl_MEMLOCK){ 

 

    int fd,odczytano; 

    char bufor[MAXCONFBUF]; 

    char *poz,*first=bufor; 

 

background image

24 

 

    fd=open(nazwa_pliku,O_RDONLY); 

    if(fd>0){ 

      odczytano=read(fd,(void *)bufor,MAXCONFBUF); 

      if(odczytano>0){ 

           poz=bufor; 

           if(atoi(poz)=>0){ 

              rl_CPU->rlim_cur=atoi(poz);  

 

 

 

  rl_CPU->rlim_max=rl_CPU->rlim_cur; 

 

 

   } 

           else rl_CPU->rlim_max=rl_CPU->rlim_cur=RLIM_INFINITY; 

 

           poz=index(poz,',');if(!poz) return -1; poz++; 

           if(atoi(poz)=>0){ 

             rl_FSIZE->rlim_cur=atoi(poz); 

             rl_FSIZE->rlim_max=rl_FSIZE->rlim_cur; 

           } 

           else rl_FSIZE->rlim_max=rl_FSIZE->rlim_cur=RLIM_INFINITY; 

 

 

           poz=index(poz,',');if(!poz) return -1; poz++; 

           if(atoi(poz)=>0){ 

              rl_DATA->rlim_cur=atoi(poz); 

              rl_DATA->rlim_max=rl_DATA->rlim_cur; 

           } 

           else rl_DATA->rlim_max=rl_DATA->rlim_cur=RLIM_INFINITY; 

 

 

           poz=index(poz,',');if(!poz) return -1; poz++; 

           if(atoi(poz)=>0){ 

              rl_STACK->rlim_cur=atoi(poz); 

              rl_STACK->rlim_max=rl_STACK->rlim_cur; 

           } 

           else rl_STACK->rlim_max=rl_STACK->rlim_cur=RLIM_INFINITY; 

 

           poz=index(poz,',');if(!poz) return -1; poz++; 

           if(atoi(poz)=>0){ 

              rl_CORE->rlim_cur=atoi(poz); 

              rl_CORE->rlim_max=rl_CORE->rlim_cur; 

           } 

           else rl_CORE->rlim_max=rl_CORE->rlim_cur=RLIM_INFINITY; 

 

           poz=index(poz,',');if(!poz) return -1; poz++; 

           if(atoi(poz)=>0){ 

              rl_RSS->rlim_cur=atoi(poz); 

background image

25 

 

              rl_RSS->rlim_max=rl_RSS->rlim_cur; 

           } 

           else rl_RSS->rlim_max=rl_RSS->rlim_cur=RLIM_INFINITY; 

 

           poz=index(poz,',');if(!poz) return -1; poz++; 

           if(atoi(poz)=>0){ 

              rl_NPROC->rlim_cur=atoi(poz); 

              rl_NPROC->rlim_max=rl_NPROC->rlim_cur; 

           } 

           else rl_NPROC->rlim_max=rl_NPROC->rlim_cur=RLIM_INFINITY; 

 

           poz=index(poz,',');if(!poz) return -1; poz++; 

           if(atoi(poz)=>0){ 

              rl_NOFILE->rlim_cur=atoi(poz); 

              rl_NOFILE->rlim_max=rl_NOFILE->rlim_cur; 

           } 

           else rl_NOFILE->rlim_max=rl_NOFILE->rlim_cur=RLIM_INFINITY; 

 

           poz=index(poz,',');if(!poz) return -1; poz++; 

           if(atoi(poz)=>0){ 

              rl_MEMLOCK->rlim_cur=atoi(poz); 

              rl_MEMLOCK->rlim_max=rl_MEMLOCK->rlim_cur; 

           } 

           else rl_MEMLOCK->rlim_max=rl_MEMLOCK->rlim_cur=RLIM_INFINITY; 

 

           return 1; 

      } 

       else{ log_err("blad odczytu informacji\n"); return -1; } 

      close(fd); 

    } 

    else{    

log_err("crit: nie mozna znalezc pliku konfiguracyjnego\n");  

return -1;  

    } 

 

Deklaracja zmiennych przetrzymujących informacje o pliku konfiguracyjnym i informacje 

o limitach odczytanych z tego pliku. 

struct stat prg_info1;  /* konfiguracja - limit  info holder       */ 

struct rlimit rl_CPU, rl_FSIZE, rl_DATA, rl_STACK, rl_CORE, rl_RSS, rl_NPROC, 

rl_NOFILE, rl_MEMLOCK; /* Limity programu  */ 

 

background image

26 

 

Sprawdzenie  czy  pliku  konfiguracyjny  limitów  nie  jest  zapisywany  przez  użytkowników 

innych niż właściciel: 

if (((lstat(M

AXCONFPATH, &prg_info1)) != 0) || 

(S_ISLNK(prg_info1.st_mode))) { 

 

log_err("error: Nie moge uzyskac informacji o pliku : (%s)\n",MAXCONFPATH); 

exit(127); 

 

 

if ((prg_info1.st_mode & S_IWOTH) || (prg_info1.st_mode & S_IWGRP)) { 

log_err("error: plik jest zapisywalny przez innych niz 

wlasciciel\n",MAXCONFPATH); 

        

exit(128); 

    }

 

 

 

 

Odczytanie pliku konfiguracyjnego i ustawienie limitów. W przypadku błędu wypisywany 

jest  komunikat  o  błędzie  do  logów  i  kończony  jest  program  (nie  sprawdzana  jest  poprawność 

wykonania  funkcji  setrlimit()  –  rozbudowując  kod  można  dodać  obsługę  błędów,  którym 

źródłem jest funkcja setrlimit()). 

 

if(odczytaj_limit(MAXCONFPATH, &rl_CPU, &rl_FSIZE, &rl_DATA, &rl_STACK,      

&rl_CORE, &rl_RSS, &rl_NPROC, &rl_NOFILE, &rl_MEMLOCK)>0){ 

            //ustawianie limitow 

            setrlimit(RLIMIT_CPU,&rl_CPU); 

            setrlimit(RLIMIT_FSIZE,&rl_FSIZE); 

            setrlimit(RLIMIT_DATA,&rl_DATA); 

            setrlimit(RLIMIT_STACK,&rl_STACK); 

            setrlimit(RLIMIT_CORE,&rl_CORE); 

            setrlimit(RLIMIT_RSS,&rl_RSS); 

            setrlimit(RLIMIT_NPROC,&rl_NPROC); 

            setrlimit(RLIMIT_NOFILE,&rl_NOFILE); 

            setrlimit(RLIMIT_MEMLOCK,&rl_MEMLOCK); 

      } 

      else{ 

        log_err("crit: blad w konfiguracji limitow\n"); 

        exit(126); 

      } 

background image

27 

 

 

background image

28 

 

 

6. Wnioski 

Niestety nie ma uniwersalnej  metody uruchamiania skryptów PHP, która nie posiadała by 

wad.  Wybierając  metodę  uruchamiania  skryptów  PHP  należy  dokonać  oceny  jak  bardzo  zależy 

nam  na  uruchamianiu  skryptów  z  uprawnieniami  właściciela  oraz  jak  duże  i  jakie  koszty 

jesteśmy  w  stanie  poświęcić  chcąc  rozwiązać  ten  problem.  Uruchamianie  programów  z 

wykorzystaniem  suexec  wiąże  się  z  narzutami  związanymi  z  uruchamianiem  nowego  procesu 

wady  tej  nie  mają  skrypty  uruchamiane  przez  moduł.  Ten  jednak  sposób  uniemożliwia  bez 

uruchamiania  nowego  serwera  na  innym  porcie  uruchomienia  skryptów  z  uprawnieniami 

właściciela.  Pewne  problemy  z  narzutem  związanym  uruchamianiem  procesów  rozwiązuje 

wykorzystanie modułu i biblioteki FastCGI, ale ta przechowuje w pamięci dużo procesów, które 

cały czas zajmują pamięć. 

Analiza  kodu  suexec  daje  nam  do  zrozumienia  jak  bardzo  ważną  częścią  w 

oprogramowaniu  serwera  są  kody  poświęcone  bezpieczeństwu.  W  zasadzie  cały  kod  programu 

suexec  służy  do  sprawdzenia  czy  został  on  wywołany  w  prawidłowy  sposób  nie  dając 

możliwości włamania się do systemu. 

Tryb safe mode daje nam pewną możliwość poprawy bezpieczeństwa pracy na serwerze z 

wieloma użytkownikami, którym nie można zaufać. Tryb safe mode staje się cennym narzędziem 

w  przypadku,  gdy  użytkownicy  piszący  skrypty  nie  mają  dostępu  do  całego  systemu  plików 

serwera  (np.  dostęp  tylko  po  przez  ftp  z  chrootem)  oraz  możliwości  wykorzystania  innych 

narzędzi  np.  skryptów  CGI  napisanych  w  Perlu,  które  pozwolą  na  dostęp  do  obszarów  serwera 

poza  swoim  katalogiem domowym (lub wyznaczonym obszarem systemu plików). Zabezpiecza 

to  np.  przed  dostępem  do  skryptów  lub  plików  oraz  np.  haseł  w  nich  zawartych  innego 

użytkownika.  Trudno  jest  tego  dokonać  inną  metodą  np.  modyfikując  uprawnienia  w  systemie 

plików ponieważ skrypty muszą być dostępne do odczytu dla serwera Apache (czyli praktycznie 

dla każdego użytkownika). Można oczywiście wykorzystać skrypty CGI oraz suexec i zapisywać 

hasła  w  plikach  tylko  do  odczytu  dla  właściciela,  ale  wiąże  się  to  z  narzutami  na  tworzenie 

nowych procesów. 

Podsumowując.  Aby  wybrać  właściwy  sposób  uruchamiania  skryptów  PHP  i  co  za  tym 

idzie konfiguracji serwera należy nie tylko znać  konfigurowane oprogramowanie, ale także cel, 

zasadę działania oprogramowania, które będzie uruchamiane przez serwer.  

 

background image

29 

 

 

7. Literatura 

8.  Dokumentacja serwera Apache: http://httpd.apache.org/docs/ 

9.  Dokumentacja PHP: http://www.php.net/manual/en/ 

10.  Dokumentacja FastCGI http://www.fastcgi.com/devkit/doc/fcgi-perf.htm 

11.  Ben, Peter Laurie „Apache przewodnik encyklopedyczny” - Helion 2000 

12.  Listy dyskusyjne