Locked History Actions

Albert Gaidamovič

PHP saugumas

1.ĮVАDАS

  • Dirbdami kompiuteriu internete, galime ne tik naudotis neaprėpiamu informacijos kiekiu, bet ir susidurti su internete egzistuojančiais pavojais. Laikai, kai Internetu naudojosi tik kompiuterius gerai išmanantys specialistai seniai praeityje. Tą supranta kiekvienas, tame tarpe ir kibernetiniai nusikaltėliai. Lygiai taip pat kaip bandome apsaugoti save, savo artimuosius bei mūsų turtą nuo nusikaltėlių tikrame gyvenime, kai kurių panašių veiksmų reikia imtis ir interneto erdvėje.

Dirbant internete galimi tokie pavojai: • jūsų kompiuteryje esantys duomenys gali būti pavogti; • į jūsų naudojamas paslaugų paskyras gali būti įsilaužta; • jūsų tapatybė gali būti pasisavinta; • jūs galite būti stebimas trečiųjų asmenų; • jūs galite nukentėti materialiai; • jūsų kompiuteris gali tapti „zombiu“ ir vykdyti atakas prieš kitas sistemas jums nežinant.

Šiame referate aprašysiu kaip reikia saugiai programuoti, populiarią PHP programavimo kalbą. PHP – plačiai paplitusi dinaminė interpretuojama programavimo kalba (en: Hypertext Preprocessor), sukurta 1995 m. ir specialiai pritaikyta interneto svetainių kūrimui. PHP sintaksė panaši į daugelį struktūrinių kalbų, ypač į C bei Perl. PHP kalba yra atviro kodo ir tai yra viena priežasčių, dėl ko kalba yra nors ir nesudėtinga, bet gana lanksti – veikia daugumoje operacinių sistemų, palaiko nemažai reliacinių duomenų bazių bei veikia su dauguma interneto serverių – CGI, FastCGI, ISAPI ir kitais protokolais. Nors PHP yra dažniausiai naudojama interneto puslapių kūrimui, bet yra labai galingas įrankis atlikti kitas funkcijas komandinėje eilutėje.

2.PHP slaptažodžių saugumas

  • Kiekvienam programuotojui neišvengiamai tenka susidurti su vartotojo identifikacijos problema. Tradiciškai lankytojo tapatybės nustatymui naudojama vartotojo vardo ir slaptažodžio kombinacija. Vartotojo vardas ir slaptažodis dažniausiai saugomi duomenų bazėje. Tačiau pradedantiesiems dažnai vis dar iškyla klausimų kaip saugiai išsaugoti slaptažodį. Apžvelkime įvairius būdus, kurie dažnai taikomi saugojant slaptažodžius.

2.1 Saugojimas taip kaip įvedė vartotojas

Įvedus vartotojui savo slaptažodį jis tiesiog išsaugojamas duomenų bazėje tiesiai iš $_POST masyvo. Prisijungimo metu atliekamas palyginimas:

if ($_POST["password"] == $password) {

  • prisijungimas();

} else {

  • neteisingai();

}

  • Toks būdas yra labai paprastas ir dažnai pasirenkamas pradedančiųjų programuotojų. Taip pat jei nenorima kurti slaptažodžio pakeitimo modulio, tuomet galima vartotojui lengvai priminti slaptažodį. Tačiau tai yra pats pavojingiausias saugojimo mechanizmas! Dažnai vartotojai naudoja tą patį slaptažodį įvairiuose puslapiuose. Jeigu duomenų bazė bus pavogta įsilaužėlių arba kenkėjų darbuotojų, jūsų klientų tapatybės kituose portaluose gali būti perimtos! Taip nutikus ir šiam faktui išlindus į viešumą jūsų reputacija bus nepataisomai sužlugdyta. Kartais yra manoma, kad duomenų bazė niekada nebus pavogta ir ši problema yra ignoruojama. Tačiau kiekvienais metais net ir didžiausių kompanijų portalai yra kompromituojami ir jų duomenys paviešinami.

2.2MD5 hash saugojimas

  • Šį būdą dažniausiai pasirenka pradedantys programuotojai nesenai sužinoję apie slaptažodžių hashing (). Šiuo būdu bet kokio ilgio įvestas slaptažodis konvertuojamas į visuomet tiek pat skaitmenų turintį skaičių. Šis dvejetainis skaičius tuomet konvertuojamas į šešioliktainį skaičių ir jis išsaugojamas kaip simbolių eilutė (angl. string). Jeigu slaptažodis bus visuomet toks pat, tuomet gautas hash rezultatas taip pat bus visuomet toks pat.
  • MD5 yra tiesiog viena iš labiausiai paplitusių hash funkcijų. Šiuo būdu duomenų bazėje niekada nesaugomas vartotojų įvestas slaptažodis, o saugomas tik hash rezultatas. Prisijungimo metu vartotojas įveda savo tikrą slaptažodį, o serverio dalyje jis transformuojamas su MD5 funkcija ir palyginamas su duomenų bazėje esančiu MD5. Jeigu MD5 hash sutampa tuomet vartotojas įvedė tikrai savo slaptažodį.

Į duomenų bazę patalpinama: $hash = md5($_POST["slaptazodis"]);

Prisijungimo metu:

$hash = $vartotojas["hash"]; if (md5($_POST["slaptazodis"]) == $hash) {

  • prisijungimas();

} else {

  • neteisingai();

}

  • Šis metodas remiasi tuo, kad iš hash rezultato neįmanoma išgauti tikro slaptažodžio. Taip pat hash reikšmė bus unikali ir niekada nebus gauta įvedus kitą slaptažodį.

Tačiau MD5 hash funkcija nebėra saugi! Ji yra labai greita ir su šiuolaikinėmis vaizdo plokštėmis galima išbandyti labai daug slaptažodžių itin greitai. Taip pat visos MD5 reikšmės jau suskaičiuotos ir galima atlikti paprastą patikrinimą lentelėje norint sužinoti slaptažodį. Šis metodas yra ne ką saugesnis nei saugojant slaptažodį tokį patį kaip įvedė vartotojas! Naudojant šį būdą jūs rizikuojate savo reputacija.

2.3 SHA1 hash saugojimas

  • Šis metodas yra panašus kaip ir MD5. Duomenų bazėje taip pat saugojamas tik hash rezultatas gautas su SHA1 funkcija. Tokį metodą naudoja pradedantieji programuotojai, kurie girdėjo, kad MD5 funkcija yra nesaugi. SHA1 hash funkcija sugeneruoja daugiau simbolių turintį rezultatą nei MD5. Tai sumažina tikimybę, kad kitas slaptažodis sugeneruos tokį pat rezultatą. Tačiau SHA1 funkcija šiuolaikiniais standartais yra pakankamai greita. Praradus duomenų bazę įsilaužėliai gana greitai aptiks tikrus vartotojų slaptažodžius. Daugelis saugumo ekspertų nerekomenduoja naudoti šios funkcijos saugojant slaptažodžius. Naudojant šį būdą jūs rizikuosite savo reputacija!

2.4 Saugojimas naudojant PHP5.5

  • PHP5.5 versijoje pridėtos slaptažodžių saugojimo ir patikrinimo funkcijos labai su paprastinančios

programuotojo darbą. Jos savyje turi pačias naujausias saugumo praktikas. Naudojant šį metodą net ir praradus duomenų bazę jūsų vartotojų slaptažodžiai išliks saugūs. Įsilaužimo atveju jūsų reputacija bus pažeista, tačiau pataisoma.

Slaptažodžio saugojimas

$hash = password_hash($_POST["slaptazodis"], PASSWORD_DEFAULT);

Slaptažodžio patikrinimas:

$hash = $vartotojas["hash"]; if (password_verify($_POST["slaptazodis"], $hash)) {

  • prisijungimas();

} else {

  • neteisingai();

}

password_hash() funkcijai perduodamas PASSWORD_DEFAULT parametras nurodo, kad naudoti bcrypt kriptografinį algoritmą. bcrypt buvo sukurtas dabar Google dirbančio Niels Provos ir paremtas Blowfish šifru. bcrypt priklauso "key derivation" funkcijoms ir yra skirtas saugoti slaptažodžiams.

Bcrypt rezultatas atrodo šitaip: "$2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a" Pradžioje esantis "$2y$10$" nurodo bcrypt versiją ($2y) ir cost ($10$). Cost nurodo kiek kartų reikia kartoti funkciją (10 reiškia kartoti 2^10 kartų).

  • Taip pat bcrypt algoritmas savyje inkorporuoja "salt" mechanizmą. Salt sugeneruojamas atsitiktinai ir pridedamas kartu į bcrypt rezultatą. Algoritmo vykdymo metu visuomet panaudojama salt reikšmė. Kiekvienas bcrypt rezultatas turi turėti skirtingą salt. Tai išsprendžia problemą, kuri dažnai sutinkama MD5 ir SHA1 algoritmuose, dar kitaip vadinamą Rainbow tables attack. Tai reiškia, kad esant net ir tam pačiam slaptažodžiui su bcrypt rezultatas bus skirtingas kiekvienam vartotojui. Įsilaužėliai turės kiekvieno vartotojo slaptažodį spėti iš naujo. Tikimybė, kad bcrypt rezultatas bus neunikalus yra labai maža. Taip pat šios funkcijos cost parametras užtikrina, kad rezultato gavimas bus lėtas. Įsilaužėliams atspėti slaptažodžius pasinaudojant serverių fermomis bus labai sunku.

Rekomenduojama parinkti cost parametrą tokį, kad vieno bcrypt rezultato gavimas jūsų serveryje užtruktų 100 ms. Surasti tinkamą cost parametrą galite šitaip:

<?php $timeTarget = 0.1; // 100 milliseconds

$cost = 8; do {

  • $cost++; $start = microtime(true);

    password_hash("test", PASSWORD_BCRYPT, ["cost" => $cost]); $end = microtime(true);

} while (($end - $start) < $timeTarget);

echo "Cost parametras: " . $cost . "\n"; ?>

Perduoti cost parametrą:

$hash = password_hash($_POST["slaptazodis"], PASSWORD_BCRYPT, array("cost" => 10));

2.5 Vartotojų identifikacija naudojant Laravel 4.2

Jei esate Laravel framework naudotojas saugus vartotojų valdymas yra itin paprastas. Slaptažodžio saugojimas:

$password = Hash::make(Input::get('slaptazodis'));

Vartotojo prisijungimas:

$username = Input::get('vartotojas'); $password = Input::get('slaptazodis'); if (Auth::attempt(array('username' => $username, 'password' => $password))) {

  • prisijungimas();

} else {

  • neteisingai();

}

2.6 Kiti būdai

  • Net ir sudėtingi slaptažodžiai anksčiau ar vėliau gali būti atspėti. Nuo šių atakų apsisaugoti paskutiniu metu itin išpopuliarėjo “captchas”, tai yra raidžių ir skaitmenų seka, kurią privalo įvesti vartotojas, norėdamas prisijungti. Ši seka turi būti sugeneruojama į paveikslėlį su įvairiais iškraipymais, ir kaskart turi būti pateikiama skirtingas atsitiktinių simbolių kratinys. Tai leidžia žinoti, kad sėkmingai prisijungs tik žmogus, kuris sugebės atpažinti raides ir skaičius, bet to nesugebės padaryti kenkėjiškas kompiuterinis skriptas.
    • Prisijungimo saugumą padidina ir elementarus skaitiklis. Bandymai prisijungti išsaugomi, ir tarkim, po 3 nesėkmingų sykių vartotojas tam tikram laikui yra deaktyvuojamas, tai yra negali prisijungti iš viso, o galbūt net privalo kreiptis į sistemos administratorius, kad rankiniu būdu būtų aktyvuotas vėl. Tai gali būti nepatogu vartotojams, tačiau labai naudinga galimybė. Sekdami vartotojo prisijungimus, laiką, IP adresus, žinosite kas ir kaip naudojasi sistema. Jei aptinkate didelį nesėkmingų bandymų prisijungti skaičių iš vieno IP adreso, galite jį tiesiog užblokuoti. Gal verta dėmesio galimybė ir suteikti prisijungimą tik iš nurodytų adresų, o visus kitus blokuojant? Paprasta, nepatogu, tačiau labai saugu.
  • Jeigu norima užtikrinti savo klientų duomenų saugumą tuomet privaloma naudoti saugius slaptažodžių saugojimo būdus. To neatlikus jūs rizikuojate savo reputacija. Patirtis rodo, kad praradus reputaciją ją susigrąžinti klientų akyse yra labai sunku. Taigi jeigu rašote savo aplikaciją naudokite PHP5.5 funkcijas password_verify() ir password_hash(). Jeigu naudojate Laravel pasinaudokite siūlomais vartotojų identifikavimo mechanizmais. Ir naudotis papildomais saugumo metodais.

3.Nesaugios PHP funkcijos

  • PHP turi funkcijų, kurios gali atlikti sistemos nustatymus ar bendrauti su kitomis programomis. Jei žinote, kad jomis vistiek nesinaudosite, rekomenduojama jas išjungti.
  • Pavyzdžiui, funkcija eval() stringą interpretuoja kaip PHP komandą ir ją įvykdo. Jei šioje funkcijoje naudojami vartotojo įvedami duomenys, jis gali pridaryti nemažai žalos. Be itin atidaus įvedimo tikrinimo, vartotojas gali paleisti bet kokią programą.
    • Pirmiausia, reikia vengti naudoti eval() funkciją. PHP leidžia php.ini faile su direktyva “disable_functions” leidžia per kablelį nurodyti visas funkcijas, kurių vartojimas turi būti draudžiamas. Dažniausiai atjungiamos tokios funkcijos kaip: ini_set(), exec(), fopen(), popen(), passthru(), readfile(), file(), shell_exec(), system(). Dažnai verta įjungti ir safe_mode režimą serveryje. Šis režimas nurodo PHP apriboti funkcijų ir operatorių naudojimą, kurie gali sukelti problemų. Nuo to nukenčia funkcionalumas, tačiau jei įjungus safe_mode, skriptai vistiek tvarkingai veikia, šį nustatymą verta palikti. Saugaus režimo ir nesaugių funkcijų atjungimas yra būtinas hostingo kompanijose, kur vienu serveriu naudojasi daugelis vartotojų.

Antra dalis baigta. Didžiosios dalies saugumo problemų paprastai išvengiama tiesiog atidžiai tvarkantis su vartotojo įvedamais duomenimis. Jei Jūs galite tikėtis paties blogiausio ir pačių pikčiausių hakerių, vadinasi galite susitvarkyti su bet kuo. 4.Failų apsaugojimas

  • Didžioji dalis web hostingo kompanijų serverių konfigūracijų yra lengvai nuspėjamos. Lygiai taip pat yra nuspėjami ir web tinklapių kūrėjai. Tarkime, galime nesunkiai atspėti, kad įterpiami failai (include’inami) guli www.saitas.lt/includes kataloge. Jei serveris nėra tinkamai sukonfiguruotas ar kitais būdais apsaugotas, mes, kreipęsi į šį katalogą, galime matyti visus jame gulinčius failus. Įsivaizduokime, jog norime kad skirtingi mūsų puslapio skriptai bendrautų su duomenų baze, todėl sukuriame bendrą nustatymų failą, pavadiname jį “dbconnect.inc” arba panašiai ir įkeliame jį i “includes” katalogą. Deja, taip daro daugelis žmonių. Dažniausiai web serveris tokius failus supranta kaip default tekstinius, todėl davę užklausą į tokį failą, mes galėsime matyti prisijungimo į duomenų bazę duomenis.
    • Nuspėjamų pavadinimų failus nerekomenduojama talpinti į nuspėjamas vietas. Išeitis gali būti iškelti juos iš web serverio root katalogo, tokiu būdu nebus galima pasiekti jų iš išorės. Kad padidinti saugumą, galime jį taip pat užvadinti sunkiau nuspėjamu pavadinimu, taip pat, laikant katalogus web serverio pasiekiamumo ribose, būtina sudėti index.html failus, kurie būtų bent jau tušti, tokiu būdu neleidžiant matyti katalogo turinio. PHP skriptuose niekada nenaudokite “.inc” failų plėtinių, pervadinkite juos į “.inc.php”. Tai užtikrins, kad failas būtų interpretuojamas PHP varikliuko, ir slaptažodžiai nepateks į ekraną. Net jei ir serveryje įvesta konfigūracija draudžianti gauti katalogo turinį (list), būtinai turėkite index.html failą, taip nereiks sukti galvos pasikeitus serverio nustatymams arba hostingo tiekėjui. Be abejo, dar stipriau yra iškart turėti ir .htaccess failus, kurie draustų matyti katalogo turinį.

Pasinaudoti minėtomis saugumo spragomis net nebūtina spėlioti - pakanka pateikti tinkamas užklausas googlui.

5.PHP kintamųjų saugumas

Kuriant visuomet įsijunkite pilną klaidų rodymą, kuris leis pamatyti apie neaprašytus kintamuosius: error_reporting(2047) Serverio nustatymuose išjunkite register globals, kurie neleis kintamųjų inicializuoti per get/post parametrus. Jei to nepadarysite, gali būti tokia situacija: //kažkas pradžioje if ($_POST[‘user’] == ‘adminas’ && $_POST[‘passwd’] == ‘admino_slaptazodis’) {

  • $prisijunges = 1;

} if ($prisijunges) {

  • // rodom admino interfeisą ir atliekam veiksmus // ….

} // kažkas gale Vartotojas gali perduoti kintamąjį $prisijungęs GET metodu, naršyklėje įvedęs ’skriptas.php?prisijunges=1′ ir taip matys prisijungusiojo turinį. Kitose situacijose, galima įterpti ne Programuojant būtina rašyti viską tvarkingai. Tai ne tik svarbu dėl to, kad programa turi gražiai atrodyti (pvz.PEAR Coding Standards), bet ir teisingai pavadinti kintamieji. Jei jūs kintamąjį pavadinsite kokiu $xxx, tai garantuoju po mėnesio nei jūs, nei jūsų kolegos greitai negalės prisiminti, ką jis savyje laiko. Daug teisingiau naudoti suprantamus pavadinimus, kad ir $kaina, $pavadinimas, $prekes. Bet viskas atrodys dar gražiau ir bus patogiau, jei pirmąjį kintamojo simbolį paskirsite aprašyti duomenų tipui. Tad, kai reikės jį panaudoti iškart žinosite, kas turi jame būti. Pavyzdžiui: $iMetai = 2015; // integer $sPavadinimas = “AJAX”; // string $aPrekes = array(1,2,3); // array $oMail = new MailClass; // objektas $fKaina = 555.95 // float Kaip minėjau šiek tiek anksčiau, duomenimis iš vartotojo reikia kuo mažiau pasitikėti. Visų pirma reiktų išjungti galvos skausmą magic_quotes, kuri uždeda stebuklingus simbolius ant kabučių ir pan. Jei negalite keisti serverio nustatymų - pasinaudokite šiuo kodo gabaliuku, kurį reiktų įdiegti pačioje pradžioje. if (get_magic_quotes_gpc()) {

  • function stripslashes_deep($value) {
    • $value = is_array($value) ?
      • array_map(’stripslashes_deep’, $value) : stripslashes($value);
      return $value;
    } $_POST = array_map(’stripslashes_deep’, $_POST); $_GET = array_map(’stripslashes_deep’, $_GET); $_COOKIE = array_map(’stripslashes_deep’, $_COOKIE); $_REQUEST = array_map(’stripslashes_deep’, $_REQUEST);

} Prieš dirbant su kintamaisiais nepamirškite apdoroti jų, nes juk vartotojas gali juos pakeisti savo nuožiūra, o ne vaikščioti per nuorodas. Tad būtina patikrinti duomenis taip, kad galimos reikšmės būtų tik tos, kurios yra galimos. Sutikite, perkant e-shop’e prekių kiekis negali būti neigiamas, tiesa? if (isset($_GET[‘news_id’]) && is_numeric($_GET[‘news_id’])) {

  • //.. bandom ieškoti naujienos id

    $aNewsData = $db->getRow(“SELECT * from naujienos where id=’”. $_GET[‘news_id’] .“‘”); if ($aNewsData) {

    • // atvaizduojam naujieną
    } else {
    • // naujiena nesurasta
    }

} Patarčiau nenaudoti tokio tipo apsisaugojimo, kurį padarė valstybinio puslapio programuotojai po jų svetainės patikrinimo per saugumo konferenciją. Su (int) jie pavertė kintamąjį į integer tipą, bet ši svetainė vis vien liko pažeidžiama XSS tipo atakomis. $aNewsData = $db->getRow(“SELECT * from naujienos where id=’”. (int)$_GET[‘news_id’] .“‘”); if ($aNewsData) {

  • // atvaizduojam naujieną

    echo “<input type=’hidden’ name=’news_id’ value=’”. $_GET[‘news_id’].“‘/>”; // .. ir t.t

} else {

  • // naujiena nesurasta

} PHP validacijai/apdorojimui turi ne vieną: is_array, is_numeric, is_bool, is_object, is_string,

6.Išvados

  • Kurdami bet kokią programą ir, tiesa pasakius, bet kuria programavimo kalba reikia būti iš dalies paranoiku. Visa gaunama informacija iš vartotojo yra nepatikima. Tad ji kiekvieną kartą privalo įgyti jūsų pasitikėjimą. Manyčiau, reikėtų atkreipti dėmesį į šiuos faktus:

• Vartotojas nežino kaip veikia programa, nežino ką žinot jūs, jis gali atlikti veiksmus tokius, dėl kurių vėliau programa atliks neįtikėtinus veiksmus. • Vartotojas gali stengtis ieškoti klaidų ir panaudoti tai savo tikslams. • Internetas ne visuomet gerai veikia. Tai jis per lėtas, tai nenusiunčiami visi paketai, dėl to jūsų programinis kodas gali veikti neįtikėtinai keistai. • Pati programavimo kalba gali turėti klaidų apie kurias jūs net nežinote, o jei žinote ir naudojat per senas PHP versijas galite nukentėti ir dėl to.

Ir dar kiti neįtikėtini veiksniai, kurie nepriklauso nuo jūsų bei jūsų įpročių. Niekas negimė mokėdamas. Blogiausia, kad turbūt visi mes mokomės iš savo klaidų. Yra tikras menas išmokti mokytis iš kitų klaidų arba atradimų.

7. LITERATŪRA

1. http://www.esaugumas.lt/lt/saugus-darbas-internete.html 2. http://lt.wikipedia.org/wiki/PHP 3. http://pixel.lt/php-saugumas-saugus-programinis-kodas-1-dalis.html 4. http://pixel.lt/php-saugumas-saugus-programinis-kodas-2-dalis.html 5. https://uzdarbis.lt/t323788/php-slaptazodziu-saugumas


CategoryHomepage