Hrvatska akademska i istraživačka mreža
  NASLOVNICA MAPA WEBA TRAŽILICA KONTAKTI CARNET WEB
Hrvatska akademska i istraživačka mreža
 
menu 4
Sigurnost
menu 4
Distribucija
menu 4
Pomoć
menu 4
Dokumenti
menu 4
menu 4

 

 

7-02-05 12:06
Apache/PHP i sigurnost

piše NINO KATIĆ

Sigurnost PHP aplikacija može se promatrati iz više kuteva, poput npr. aplikativnog ili sistemskog, ali svima je zajedničko da je, ako je ugrožena, opasnost za ispravan rad i aplikacije i čitavog sustava.

Gledajući iz aplikativnog kuta, loše napisan kod u kombinaciji s loše konfiguriranim PHP-om može uzrokovati mnoge probleme poput XSSa (Cross Site Scriptinga), session hijackinga, SQL injectiona itd. Tema ovoga teksta ipak nije pogled iz tog kuta, nego iz sistemskog. Kod njega je sigurnost izvođenja PHP aplikacija izravno vezana s načinom instalacije i konfiguracije PHP-a, i Apachea. Unutar same teme obrađujemo više načina na koji PHP može biti instaliran, spominjemo dodatne module koji će poboljšati sigurnost, te izlažemo primjere mogućih napada. Sve to pod pretpostavkom o dijeljenom (shareanom) serveru na kojem korisnici imaju shell pristup.

 


Pregled tipova često korištenih instalacija PHP-a i Apachea:

 

PHP instaliran kao CGI ili Apache modul 1.3.x
PHP kao modul sa patchanim Apacheom 1.3.x
PHP CGI wrapper
PHP kao modul za Apache 2.0.x
PHP sa Zend encoderom
PHP sa dodatnim opcijama, trikovima

PHP instaliran kao CGI ili Apache modul 1.3.x

Problem koji se pojavljuje u prvom slučaju, kod kojeg se dakle radi o defaultnoj instalaciji PHPa i Apachea (CGI), pokušava se riješiti nekim od nabrojanih načina. O čemu se zapravo radi? Prilikom zahtjeva za PHP skriptom, web server (Apache) poziva PHP interpreter koji zatim izvršava PHP kod. Bitno je da se skripta izvršava pod UID-om Apachea (npr. nobody, www-data, apache), što znači da je nad .php datotekama potrebno postaviti takve dozvole koje će omogućiti Apacheu čitanje istih tih datoteka.

 

Primjer 1.

 

drwx--x--x  web root (/home/pperic/public_html/)

   rw-r--r--  pperic:users    index.php

 

Ovdje se vidi da su dozvole nad web root direktorijem postavljene tako da grupi i ostalima omogućuju samo izvršavanje (execute) skripti što je sasvim dovoljno za ispravno funkcioniranje index.php skripte.

Pretpostavimo da se u index.php datoteci nalazi username i password s kojim se iz iste skripte korisnik pperic spaja na bazu. Potencijalni korisnik dduric želi se dokopati u/p i napraviti štetu. Što u ovom slučaju on može napraviti? dduric će jednostavno u browseru učitati stranicu i pretpostaviti da se radi o index.php datoteci, budući je to default kojeg poziva Apache, ako se u URL-u ne navede naziv skripte. Nakon toga skriptu će jednostavno pročitati sa npr. less /home/pperic/public_html/index.php. dduric se dokopao u/l kombinacije. Kako se zaštiti?

 

 

Ne previše efikasna mjera bila bi postavljanje index.php datoteke u vlasništvo i/ili grupu apachea te postavljanje odgovarajućih dozvola:

 

rw------ apache:apache   index.php

 

ali ni to ne bi previše pomoglo, budući bi dduric jednostavnom PHP skripticom lako pristupio index.php datoteci (PHP se izvršava pod UID-om Apachea). Nešto bolji način zaštite pružilo bi postavljanje proksiranog rewritea unutar datoteke httpd.conf čije bi dozvole omogućavale čitanje samo rootu. Na taj način skriptu bismo u datotečnom sustavu nazvali nekim kompliciranjim imenom od index.php dok bi se na nju u URL-u i dalje referencirali kao index.php.

 

Primjer 2.

 

 - dduric otvara URL http://neki-site/index.php

 - Apache radi proksirani rewrite index.php u pocetna-nekihash.php, te poziva PHP koji izvršava kod

 - dduric pokušava čitanje sa less /home/pperic/public_html/index.php ali to ne uspijeva, budući je pravo ime skripte /home/pperic/public_html/pocetna-nekihash.php

 

Mana ovog načina zaštite je što običan korisnik na sistemu ne može mijenjati httpd.conf datoteku, a samo rješenje i nije suviše elegantno.

 

Kod programiranja PHP-a postoji praksa da se konfiguracijski podaci poput usernamea, passworda i sl. upisuju u datoteke smještene izvan web root direktorija. Kasnije se isti ti podaci uključuju u glavnu skriptu putem naredbe include ili require. Tako se postiže jedna razina sigurnosti time što korisnici koji nemaju shell pristup računalu na kojem se vrti PHP skripta ne mogu izravno doprijeti do navedene datoteke. Ovaj problem međutim i dalje ostaje neriješen, jer korisnici sa shell pristupom analizom skripte, u kojoj je i konfiguracijska datoteka, mogu lako zaključiti koja je njena putanja i gdje se nalazi. Budući konfiguracijska datoteka mora imati dozvole za čitanje kako bi je pročitao sam Apache, jasno je da problem ostaje visjeti u zraku.

 

Iz navedenih primjera jasno je kako je problem ozbiljan i da ga na neki način treba riješiti. U nastavku su opisana neka od mogućih rješenja.

 

PHP kao modul sa patchanim Apacheom 1.3.x

 

Razlika između CGI verzije PHP-a i PHP Apache modula između ostalih je i u brzini, zbog toga što CGI verziju web server treba učitati svaki put kada dođe do zahtjeva za PHP stranicom, dok je ona u obliku modula uvijek učitana u memoriju. Na taj način osigurava se brže interpretiranje stranice. Kada bismo Apache natjerali da PHP skripte izvršava pod UID-om usera/grupe virtualnog hosta bilo bi to značajno sigurnosno poboljšanje. Upravo to, omogućava nam patch koji možemo pronaći na: http://luxik.cdi.cz/~devik/apache/ . Ideja je da se svaki virtualni host vrti pod svojim UID-om i eventualno GID-om*, sto će Apache s instaliranim patchom iskoristiti i za pokretanje PHP skripte. Naime, skriptu će pokrenuti upravo u vlasništvu UID-a / GID-a* pod kojima se vrti navedeni virtualni host.

 

Primjer 3.

 

httpd.conf

 

<VirtualHost 169.23.23.1>

  DocumentRoot /home/pperic/public_html/

  User pperic

  Group pperic

</VirtualHost>

 

filesystem

 

drwx--x--x  web root (/home/pperic/public_html/)

   rw-------  pperic:pperic    index.php

 

Zahtjev za index.php skriptom će proći, premda file ima dozvole za čitanje postavljene samo za njenoga vlasnika, upravo zbog toga što se virtualni host vrti pod UID-om pperic a patch omogućava Apachu izvršavanje skripte pod tim istim UID-om. Iz navedenog je vidljivo da eventualni pokušaj ddurica da pročita sadržaj index.php filea neće uspjeti. Može se zaključiti da je sadržaj datoteke uspješno zaštićen. Kako bi se pokazalo da se PHP skripta vrti pod UID-om pperic pomoći će jednostavna PHP skriptica:

<?php

 $uid = posix_getuid();

 $uidinfo = posix_getpwuid($uid);

 $groupid  = posix_getegid();

 $groupinfo = posix_getgrgid($groupid);

 echo "User i grupa pod kojima se vrti skripta: ".$uidinfo["name"].":".$groupinfo["name"];

?>

 

* premda bi se PHP skripta sa patchanim Apacheom trebala vrtiti i pod GID-om virtualnog hosta, to iz nekog razloga nije slučaj (GID je i dalje defaultni), ali uz malo dodatnog napora i eventualne prepravke patcha i to bi se riješilo.

 

PHP CGI wrapper

 

PHP CGI wrapper omogućuje sličnu razinu zaštite kao i prethodno rješenje, samo što je to CGI verzija PHP-a, što je ujedno i sporije rješenje. Jedna je od prednosti takvog načina rada što neki wrapperi omogućuju izvršavanje PHP skripti pod UID/GID-om vlasnika skripte, što znači da nismo ograničeni samo na virtualne hostove. Jedno od takvih third-party ješenja je CGIWrap (http://www.umr.edu/~cgiwrap). Apache inače (native) podržava suEXEC rješenje slično navedenom CGIWrapu. suEXEC lako uključimo u Apache pri njegovom kompajliranju i to tako da configure skripti dodamo argument  --enable-suexec. Da bi ispravno funkcionirao suEXEC mora imati postavljen document root (--suexec-docroot). Pokretanje skripti će biti dozvoljeno samo ispod tog direktorija, uz iznimku user direktorija, koji će isto funkcionirati ako je ispravno iskonfiguriran (user dir module za Apache, --suexec-userdir). Virtualni host konfigurira se slično kao i u primjeru br. 3. Razlika CGIWrapa i suEXEC je u tome što CGIWrap pruža malo veću fleskibilnost nego suEXEC. Naime, CGIWrap saznaje UID/GID preko vlasnika same skripte, dok suEXEC to radi preko httpd.conf filea (konfiguracija virtualnih hostova) i ~username dijela URLa.

Osim nabrojanih, postoji podosta drugih rješenja s varijacijom na temu, s time da neka od njih cacheiranjem prilično ubrzavaju stvari (FastCGI), a neka smanjenim mogućnostima također pokušavaju naći svoje mjesto (suPHP).

 

PHP kao modul za Apache 2.0.x

 

Apache 2.x donio je prilično novosti prema verziji 1.x. Zanimljivo je da Apache 2.x ima podršku za multi-processing module (MPM) među kojima je i modul perchild koji omogućava izvršavanje virtualnih hostova pod različitim UID-ima. Mana tog modula, a koju spominju i stranice Apachea (http://httpd.apache.org/docs-2.0/mod/perchild.html) sažeta je već u prvoj rečenici: "This module is not functional." Rješenje ipak postoji, a skriva se na stranicama http://www.metux.de/mpm/. Metux MPM modul radi isto kao i modul perchild, ali za razliku od njega ovaj modul JE funkcionalan. Zanimljivo, službena stranica modula Metux MPM daje minimum informacija o samom modulu, a nema ni linka za download. Njega ćemo, kao i upute za instalaciju, pronaći na neslužbenoj stranici http://www.sannes.org/metuxmpm/. Potrebno je skinuti patch httpd-2.0.48-metuxmpm-r8.patch  te ga primjeniti na Apache. Iako je iz naziva lako zaključiti da je patch rađen za Apache 2.0.48 može ga se, bez ikakvih problema, primjeniti i na trenutno najnoviju 2.0.52 verziju. Patchiranje je jednostavno. Patch se kopira u Apacheov source direktorij, te se primjeni naredbom patch -p1 < httpd-2.0.48-metuxmpm-r8.patch. Nakon toga pokrene se ./buildconf. Nakon kompajliranja i konfiguracije Apachea možemo se gore navedenom PHP skriptom uvjeriti da se svaki virtualni host vrti pod svojim UID/GIDom.

 

PHP sa Zend encoderom

 

Ovo rješenje prilično je jednostavno za implementaciju, ali nije besplatno jer je komercijalni proizvod tvrtke Zend (www.zend.com). Uz pomoć enkodera PHP datoteke se kriptiraju nereverzibilnim algoritmom te nisu nikome čitljive. Uz pomoć Zend optimizera, besplatnog modula za web server, enkodirane datoteke izvršavaju se još brže nego bez njega. Instalacija Zend optimizera je potpuno jednostavna, pa je tako npr. na Solarisu potrebno samo pokrenuti instalacijsku skriptu te odgovoriti na nekoliko pitanja vezana uz Apache. Slično je i na ostalim UNIX/Linux OS-ovima. Više o encoderu može se pronaći na http://www.zend.com/store/products/zend-encoder.php.

 

PHP sa dodatnim opcijama, trikovima

 

Jedna od opcija koju nudi sam PHP za rješenje problema je direktiva safe_mode. Kada je uključena, PHP provjerava da li se vlasnik skripte podudara sa vlasnikom datoteke koju ta skripta otvara, piše ili briše. Slična direktiva je i open_basedir. Ona omogućava da se PHP skriptama ograniči rad sa datotekama unutar nekog određenog direktorija. Iako se čini da uz pomoć ove dvije direktive problem može biti zadovoljavajuće riješen, u praksi nije baš tako. Podosta PHP aplikacija neće ispravno raditi s tim direktivama. Osim toga, kao što je navedeno i na samim stranicama http://www.php.net/features.safe-mode, ovaj problem nije dobro rješavati na razini PHP-a, budući je on vezan uz web server. Prakično to znači da, iako će PHP skripte biti solidno zaštićene, skripte napisane u nekom drugom jeziku ostat će i dalje ranjive.

Za razliku od toga načina zaštite, postoji još jedan, možda malo manje poznat, a više spada u tricky rješenja. Kritični podaci poput usernamea i passworda smjeste se u enviroment varijable. Izvodi se tako da u neku datoteku, npr. secret.txt upišemo:

 

SetEnv DB_USERNAME "pperic"

SetEnv DB_PASSWORD "g2jfg32"

 

Nakon toga datoteku direktivom Include "/putanja/do/secret.txt" uključimo u httpd.conf i to pod određenim virtualnim hostom, tako da joj ostali korisnici ne mogu pristupiti. Vrlo je važno da datoteku secret.txt zaštitimo odgovarajućim dozvolama npr. chmod 600 secret.txt. Tako osiguravamo da je nitko osim roota ne može pročitati. Unutar PHP-a varijablama se može pristupiti na sl. način:

 

$username = $_ENV['DB_USERNAME'];

$password = $_ENV['DB_PASSWORD'];

 

Mana ovog načina je što korisnik ne može sam prčkati po datoteci httpd.conf, te je sama zaštita dosta ograničena.

Za koji način zaštite se odlučiti ovisi o samim administratorima. Apache 1.3.x još uvijek je stabilna i provjerena kombinacija s PHP-om, pa rješenja s patchiranim modulom ili CGI wrapperom može dati zadovoljavajuće rezultate. S druge strane, Apache 2.0.x je alternativa koja je u početku imala dosta problema s PHP-om, ali sada su se stvari "ispeglale" i takva se kombinacija sve više sreće. Primjer je recimo T-Com koji koristi Apache 2.0.x i custom made CGI wrapper. Zendov encoder nije loš, ali budući je komercijalan, ne može se korisnicima nametnuti kao rješenje. Osim toga, enkoder slično kao i PHP direktive safe_mode i open_basedir, rješavaju problem na drugoj razini što baš nije najbolje.

Za kraj bi bilo dobro napomenuti da nabrojani načini zaštite nisu i jedini. Razni komercijalni paketi namjenjeni su prije svega web hosting providerima koji na manje-više uspješan način osiguravaju kakvu-takvu zaštitu. Neki od njih oslanjaju se na chroot mehanizme uz pomoć kojih izoliraju korisničke direktorije i na taj način omogućavaju solidan nivo zaštite. O njima nekom drugom prilikom.

 





[Lista]
Ovu uslugu CARNeta realizira Sveučilišni računski centar Sveučilišta u Zagrebu
  Copyright ©2005. CARNet. Sva prava zadržana. Impressum.
Mail to
sys-portal@CARNet.hr