Apache, PHP saugumo priemonės


Įvadas

Apache – tai atvirojo kodo HTTP serveris, naudojamas Unix ir Windows aplinkose, kuris aptarnauja daugiau nei pusę pasaulio internetinių svetainių. Yra naudojamos trys serverio versijos: Apache 1.3, Apache 2.0 ir Apache 2.1 (beta versija).

PHP – (Hypertext Preprocessor) į internetą orientuota skriptų kalba, kurią galima įterpti į HTML tarp specialių žymių, pvz.: <?php /* PHP instrukcijos*/ ?>, <? /* PHP instrukcijos */ ?> . PHP skriptas yra interpretuojamas ir vykdomas serverio pusėje, todėl vartotojas gauna rezultatą (HTML ar XML formatu) savo naršyklėje, nežinodamas koks kodas buvo įvykdytas.

PHP į Apache gali būti įkompiliuotas kaip modulis (statiškai), užkrautas kaip dinaminis modulis arba leidžiamas kaip CGI skriptas. Kai PHP naudojamas kaip Apache modulis (dinaminis ar statinis), jis paveldi Apache vartotojui („nobody“) skirtus leidimus. Skirtingiems vartotojams priklausantys PHP skriptai vykdomi su tomis pačiomis („nobody“) teisėmis, todėl gali atsirasti saugumo problemos. Jei vartotojo PHP skriptas naudojamas priėjimui prie failo, jis turi būti prieinamas „nobody“ vartotojui. Kitas vartotojas taip pat gali parašyti PHP skriptą ir prieiti prie svetimų failų, netgi jei OS priemonėmis tokia prieiga nėra leidžiama sistemos vartotojams (chroot priemonėmis).

Skripto, atidarančio ir parodančio “/etc/passwd” failą, pavyzdys:

 

<?php
 $handle = fopen("/etc/passwd", "r");
 while (!feof($handle)) {
 $buffer = fgets($handle, 4096);
 echo $buffer;
 }

 fclose($handle);
 ?>

Tokiu pat principu gali būti perskaitytas kito vartotojo tinklapių slaptažodžių failas (.htpasswd), PHP arba CGI skriptas, su duomenų bazių slaptažodžiais ir pan.

Standartiškai pagrindinė serverio konfigūracija httpd.conf faile neriboja prieigos prie failų, todėl vartotojas negali apsaugoti savo informacijos nuo kitų vartotojų.

Šią prieigos problemą galima išspręsti derinant keletą saugą didinančių priemonių:

 

    1. open_basedir direktyvą

 

    1. safe_mode nustatymą

 

    1. Apache autentifikaciją, autorizaciją ir priėjimo kontrolę

 

    1. .htaccess failą

 

    1. apsaugą nuo cURL funkcijų

 

Saugos problemų sprendimo būdai

 

    1. open_basedir

 

open_basedir direktyva apriboja katalogus, prie kurių gali prieiti PHP skriptas. Naudojant open_basedir, leidžiama prieiti tik prie failų, esančių nurodytoje katalogų medžio vietoje.

Kai skriptas bando atidaryti failą fopen() ar gzopen() funkcijomis, patikrinama failo buvimo vieta. Jei failas yra nurodyto katalogų medžio išorėje, PHP jo neatidarys. Šis apribojimas galioja ir simbolinėms nuorodoms – jei nuoroda rodo už open_basedir katalogų medžio, priėjimas bus draudžiamas. open_basedir keliai nuo tėvinių katalogų yra automatiškai paveldimi.

Apribojimas nurodomas su open_basedir yra prefiksas, bet ne katalogo pavadinimas. Tai reiškia, kad „open_basedir = /dir/incl“ leidžia pasiekti ir „/dir/include“ bei „/dir/incls“, jei tokie egzistuoja. Norint, kad būtų galima prieiti prie failų, esančių tik nurodytoje direktorijoje, pabaigoje reikia pridėti „/“ (open_basedir = /dir/incl/).

Pvz.: httpd.conf failas:

 

<VirtualHost 192.168.0.44:80>
 DocumentRoot /home/vaida/public_html/Naktis
 ServerName www.serveris.litnet.lt
php_admin_value open_basedir /home/vaida/public_html/Naktis/
</VirtualHost>

Speciali reikšmė „.“ parodo, jog darbinė skripto direktorija bus naudojama kaip pagrindinė direktorija. Tai nėra saugu, kadangi skripto darbinė direktorija gali būti pakeista naudojant chdir() funkciją, todėl tokio nustatymo naudoti nerekomenduojame.

Ši direktyva nepriklauso nuo direktyvos safe_mode nustatymo.

Tam tikriems virtualiems serveriams open_basedir gali būti išjungta, httpd.conf faile naudojant direktyvą:

 

php_admin_value open_basedir none

 

    1. safe_mode

 

PHP direktyva „safe_mode“ padeda išspręsti saugumo problemą, kai serveriu dalinasi keli vartotojai.

Kai safe_mode aktyvuota, PHP tikrina ar paleisto skripto savininkas sutampa su atidaromo failo savininku. Jei savininkai nesutampa, arba skriptas yra ne failo savininko direktorijoje, sugeneruojamas klaidos pranešimas ir skriptas sustabdomas.

Standartiškai safe_mode vėliavėlei priskiriama reikšmė „0“ (režimas išjungtas). Dėl saugumo užtikrinimo, safe_mode turėtų būti aktyvuota.

 

    • safe_mode aktyvavimas visam serveriui, php.ini faile
      safe_mode = On

       

 

    • safe_mode aktyvavimas vienam konkrečiam virtualiam serveriui, httpd.conf faile:
      php_admin_value safe_mode On

       

 

Jei tam tam tikram skriptui reikalinga prieiti prie failo, priklausančio kitam vartotojui, nebūtina safe_mode režimo išjungti visam serveriui. Tokį išjungimą galima padaryti vieno virtualaus serverio kontekste naudojant vieną iš šių direktyvų:

 

php_admin_flag safe_mode Off

 

php_admin_value safe_mode 0

 

    1. Apache autentifikacija, autorizacija ir priėjimo kontrolė

 

Autorizacija, autentifikacija, priėjimo kontrolė – trys skirtingi būdai nuspręsti ar vartotojui davus užklausa į resursą, jam tas resursas bus grąžintas.

 

    • Autentifikacija reikalinga vartotojo tapatybei identifikuoti. Ji susieja vartotojo vardą ir slaptažodį.

 

    • Autorizacija nustato ar jau identifikuotas vartotojas turi teisę prieiti prie resurso. Autorizacijos metu tikrinama ar vartotojas priklauso tokį leidimą turinčiai grupei, ar yra tinkamas jo saugumo lygis.

 

    • Priėjimo kontrolė yra bendresnis priėjimo prie tinklo resursų kontroliavimo būdas. Priėjimas gali būti suteiktas arba atmestas atsižvelgiant į daugybę kriterijų, pvz.: kliento tinklo adresą.

 

Daugeliu atveju šios technikos yra susijusios, todėl naudojamos kartu. Jų pagalba galima priėjimą prie tam tikrų resursų leisti tik tam tikriems vartotojams.

Prieš naudojant autentifikaciją turi būti sukurtas slaptažodžių failas ir tinkamai pakeista serverio konfigūracija. Taip pat galima susikurti vartotojų grupių failą. Slaptažodžių failo kūrimas:

 

htpasswd c ~/passwords/.htpasswd username

Įvykdžius komandą, htpasswd paprašys įvesti slaptažodį ir jį pakartoti.

 

htpasswdApache paketo programa slaptažodžių           failo kūrimui.

 

    • Parametras –c naudojamas failo kūrimui. Jo nereikia nurodyti, pridedant naujus vartotojus į jau egzistuojantį slaptažodžių failą;

 

    • ~/passwords/.htpasswdslaptažodžių failas;

 

    • usernamevartotojo vardas, įtraukiamas į slaptažodžių failą kūrimo metu.

 

Naujo vartotojo įtraukimas į jau egzistuojantį failą (be –c parametro):

 

htpasswd ~/passwords/.htpasswd admin

Slaptažodžiai faile saugomi užšifruota forma.

Slaptažodžių failas turi būti skaitomas-rašomas tik savininkui, ir skaitomas tik apache procesui (vartotojui nobody). Tai galima padaryti suteikiant failui teises 640, ir nobody vartotoją padarant vartotojo grupės nariu (tačiau joks kitas sistemos vartotojas neturi būti vartotojo grupės nariu!).

Pavyzdžiui:

Administratorius:

 

root@server:~# usermod g vartotojas nobody

Vartotojas:

 

vartotojas@server:~$ htpasswd -c passwords/password.file          draugas
 New password: 
 Re-type new password: 
 Adding password for user draugas
 vartotojas@server:~$ chmod 640 passwords/password.file
 vartotojas@server:~$ ls l passwords
 total 4
 -rw-r-----1 vartotojas vartotojas 22 Jun 23 14:41 password.file

Konfigūracijos pakeitimas, kad būtų kreipiamasi į slaptažodžių failą:

 

AuthType Basic
 AuthName "Administratoriai"
 AuthUserFile /home/user/passwords/.htpasswd
 Require user vaida admin

Šios direktyvos gali būti saugomos .htaccess faile tam tikroje apsaugotoje direktorijoje arba serverio konfigūraciniame faile httpd.conf <Directory> skirsnyje. Jei konfigūracija keičiama httpd.conf faile, Apache reikia perkrauti, jei įkeliama į .htaccess failą, jos pradeda galioti iš karto. Priėjimo prie resursų leidimas suteikiamas tik nurodytiems vartotojams ir tik įvedus teisingus slaptažodžius.

Jei norima autentifikuoti grupę vartotojų, kuriamas grupės failas, kuriame išvardinami grupei priklausantys vartotojai (atskiriami tarpo simboliu), Pvz.: admin vaida guest

Konfigūracija pakeičiama taip:

 

AuthType Basic
 AuthName "Autoriai"
 AuthUserFile /home/user/passwords/.htpasswd
 AuthGroupFile /home/user/passwords/.htgroup
 Require group authors

Priėjimo kontrolei naudojamos Allow ir Deny direktyvos, kurios kontroliuoja priėjimą prie resursų pagal besikreipiančio vartotojo hosto vardą ar hosto adresą.

Direktyva Ordernurodo Apache kokia tvarka kreiptis į filtrus.

Pvz.:

 

Order Deny,Allow
 Deny from all
 Allow from hostovardas.pavyzdys.com

 

    1. .htaccess failai

 

.htaccess failai leidžia nustatyti specifinius parametrus atskiriems katalogams. Faile būna viena ar daugiau konfigūracinių direktyvų. Jis saugomas tam tikrame kataloge, ir direktyvos taikomos tam katalogui bei jo subkatalogams. Priėjimo kontrolės failo pavadinimas nurodomas httpd.conf faile AccessFileNamedirektyvoje: AccessFileName .htaccess . Standartinį failo vardą galima pakeisti.

Kokius nurodymus galima įrašyti į .htaccess failą, apibrėžia AllowOverridedirektyva. AllowOverride direktyvos sintaksė:

 

AllowOverride All|None|directive-type [directive-type].

AllowOverride galima nurodyti tik katalogui, bet ne vietai ar failui. Kai direktyvai nustatoma reikšmėNone, .htaccess failas yra ignoruojamas, serveris jo neskaito.

Mus dominantys direktyvų tipai yra AuthConfig, leidžiantis naudoti autorizacijos direktyvas (pvz.: AuthName, AuthType, Require), ir Limit, leidžiantis naudoti direktyvas, kurios kontroliuoja priėjimą prie kompiuterio (Allow, Deny, Order)

Direktyvos naudojimo pavyzdys: AllowOverride AuthConfig Limit

Autentifikacijos vykdymas .htaccess faile:

 

AuthType Basic
 AuthName "Password Required"
 AuthUserFile /home/vartotojas/passwords/password.file
 Require valid-user

.htaccess failą reikėtų naudoti tik tuo atveju, kai norima dažnai pakeisti konfigūraciją atskirose direktorijose arba nėra galimybės prieiti prie httpd.conf failo. Tuomet vartotojams suteikiama galimybė patiems keisti katalogo konfigūraciją (pvz.: jei internetinių paslaugų teikėjas talpina daug skirtingų vartotojų svetainių viename kompiuteryje, jis gali norėti, kad vartotojai patys keistų konfigūraciją).

.htaccess naudojimo reikia vengti dėl našumo ir saugumo problemų.

Našumo problema. Kai nustatoma AllowOverride, leidžianti naudoti .htaccess failus, Apache .htaccess failų ieškos kiekviename kataloge. Apache ieško .htaccess failų visuose aukštesniuose kataloguose tam, kad žinotų visas direktyvas, kurias turi vykdyti. Taigi, jei į failą kreipiamasi iš katalogo /www/htdocs/pavyzdys, Apache turės ieškoti ir šių failų:

 

/.htaccess
/www/.htaccess
/www/htdocs/.htaccess
/www/htdocs/pavyzdys/.htaccess

Vadinasi, kiekvienam priėjimui iš to katalogo reikalingi keturi papildomi kreipiniai ir .htaccess failai yra skaitomi kiekvieną kartą, kai tik kreipiamasi į dokumentą. Todėl naudojant .htaccess failus sumažėja našumas nepriklausomai nuo to, ar jie iš tikrųjų egzistuoja. Būtina kaip galima daugiau apriboti direktorijas, kuriose ieškoma .htaccess failo. Pvz.:

 

<Directory />
 AllowOverride None
 </Directory>
 <Directory /home/*/public_html>
 AllowOverride FileInfo AuthConfig Limit
 </Directory>

Pagal šias direktyvas, .htaccess failai neieškomi niekur, išskyrus vartotojų public_html katalogus.

Saugumo problema. Suteikiant vartotojams leidimą keisti serverio konfigūraciją kyla grėsmė, kad bus atlikta pakeitimų, kurių negalės kontroliuoti serverio administratorius.

Bet koks konfigūracijos pakeitimas lygiai taip pat efektyviai gali būti daromas <Directory> skirsnyje pagrindiniame serverio konfigūracijos faile httpd.conf. Pavyzdžiui:

/www/virtuals/server1/htaccess faile parašyta direktyva

 

AddType text/pavyzdys .exm

yra ekvivalentus įrašas httpd.conf faile:

 

<Directory /www/virtuals/server1>
 AddType text/pavyzdys .exm
 </Directory>

Autentifikacijos direktyvas rekomenduojama parašyti httpd.conf faile, o .htaccess naudoti tik tuo atveju, jei nėra priėjimo prie pagrindinio serverio konfigūracinio failo.

 

    1. Apsauga nuo cURL funkcijų

 

open_basedir direktyvos teikiamas saugumas gali būti pažeistas naudojant CURL funkcijas curl_init() ir curl_exec(), kurios PHP skriptui gali leisti prieiti prie failų, esančių open_basedir priskirtos direktorijos išorėje. Vartotojai, turintys teisę kurti ir modifikuoti PHP skriptus, gali apeiti open_basedir apribojimą ir naršyti po visą failų sistemą.

Pvz.: jei php.ini faile open_basedir = /var/www/html, galima perskaityti /etc/passwd pasinaudojus cURL funkcijomis.

curl.php:

 

<?php
 $ch = curl_init("file:///etc/passwd");
 $file=curl_exec($ch);
 echo $file
 ?>

/etc/passwd turinį galima pamatyti įvykdžius komandą

 

links -dump http://www.kazkoksserveris.lt/curltest/curl.php

Toks pažeidžiamumas pastebėtas PHP 4.3.8 versijoje su CURL 7.10.6, tačiau jis gali pasireikšti ir kitose versijose.

Apsisaugojimas:

 

    1. uždrausti cURL funkcijų palaikymą PHP.

 

    1. pasinaudoti programos taisiniu (patch):
      diff -ru php4-4.3.10.old/ext/curl/curl.c php4-4.3.10/ext/curl/curl.c
      --- php4-4.3.10.old/ext/curl/curl.c 2005-01-20 14:20:15.000000000 +0000
      +++ php4-4.3.10/ext/curl/curl.c 2005-01-20 15:34:06.000000000 +0000
      @@ -682,6 +682,14 @@
        WRONG_PARAM_COUNT;
        }
      + /* check open_basedir restriction */
      + {
      + char *u = Z_STRVAL_PP(url);
      + if(!u || (!strncmp(u, "file://",7) && php_check_open_basedir((u+7) TSRMLS_CC))) 
      + RETURN_FALSE;
      + }
        alloc_curl_handle(&ch);
       ch->cp = curl_easy_init();

       


 

PRIEDAI

 

    1. Virtualių hostų kūrimas Apache serveryje

 

Virtualūs hostai gali būti kuriami trimis skirtingais būdais pagal:

 

      1. skirtingus portus

 

      1. skirtingus IP adresus

 

      1. skirtingus vardus

 

Galimas ir mišrus būdas derinant išvardintus būdus tarpusavyje. Virtualių hostų (pagal skirtingus portus) sukūrimas httpd.conf faile:

 

Listen 80
 Listen 8080
 NameVirtualHost 111.22.33.44:80 
 NameVirtualHost 111.22.33.44:8080 
 <VirtualHost 111.22.33.44:80> 
 DocumentRoot /home/vaida/public_html/Diena
 ServerName server.litnet.lt 
 </VirtualHost>
 <VirtualHost 111.22.33.44:8080>
 DocumentRoot /home/vaida/public_html/Naktis
 ServerName server.litnet.lt
 </VirtualHost>

 

    1. CURL

 

CURL Client URL bibliotekos funkcijos

PHP palaiko liburl – biblioteką, kuri leidžia prisijungti prie severių, naudojančių įvairius protokolus. libcurl palaiko šiuos protokolus: http, https, ftp, gopher, telnet, dict, file, ldap. Šios funkcijos įdėtos į PHP 4.0.2.

Reikalavimai

Norint naudotis CURL funkcijomis, reikia suinstaliuoti CURL paketą.

 

    • PHP 4.2.3 – CURL 7.9.0 ar aukštesnę versiją

 

    • PHP 4.3.0 – CURL 7.9.8 ar aukštesnę versiją

 

    • PHP 5.0.0 – CURL versiją, aukštesnę nei 7.10.5

 

Instaliavimas

Norint naudotis CURL, reikia sukompiliuoti PHP su parametru curl[=DIR], kur DIR yra vieta tos direktorijos, kurioje saugomos „lib“ ir „include“ direktorijos. „include“ direktorijoje yra katalogas „curl“, kuriame saugomi  easy.h ir curl.h failai. „lib“ direktorijoje yra „libcurl.a“ failas. Pradedant nuo PHP 4.3.0 versijos, PHP galima sukonfigūruoti taip, kad CURL būtų galima naudoti URL srautams –with-curlswrappers.

Naudojimas

Kai sukompiliuojamas PHP su CURL palaikymu, galima pradėti naudoti CURL funkcijas. Pagrindinė idėja pagrįsta tokiais žingsniais:

 

    1. Inicijuojama CURL sesija, naudojant curl_init()

 

    1. Nustatomi parametrai siuntimui, naudojant curl_setopt()

 

    1. Vykdoma sesija, naudojant curl_exec()

 

    1. Baigiama sesija, naudojant curl_close()

 

curl_init – inicijuoja CURL sesiją
Apibūdinimas: curl_init() inicijuoja naują sesiją ir grąžina atsakymą, kuris bus naudojamas curl_setopt, curl_exec() ir curl_close funkcijose. Jei neprivalomas parametras urlnurodytas, CURLOPT_URL parametras nustatomas toks, kokia yra parametro vertė (automatiškai). Tai galima nustatyti ir rankiniu būdu, naudojant curl_setopt() funkciją.

curl_exec – vykdo CURL sesiją
Apibūdinimas: Ši funkcija iškviečiama po to, kai inicijuojama CURL sesija ir visos opcijos tai sesijai nustatytos. Jos paskirtis yra paprasčiausiai vykdyti anksčiau apibrėžtą CURL sesiją (paduodamą per ch).

Pvz.: naujos CURL sesijos inicijavimas ir svetainės įkėlimas į failą

 

<?php
 <$ch = curl_init(); 
 curl_setopt($ch, CURLOPT_URL, "http://www.example.com/");
 curl_setopt($ch, CURLOPT_HEADER, 0);
 curl_exec($ch);
 curl_close($ch); 
 ?>