Start

Sėdėjau aš sykį darbe, ir taip tingėjau, kad net gėda pasidarė ir sugalvojau kad reikia nuveikt kažką naudingo, nors ir tiesiogiai nesusijusio su darbu. Šis straipsnis surinktas, pakonspektuotas ir išverstas į lietuvių kalbą pagal www.ilovejackdaniels.com. Nesiekiu jokios naudos sau, ir nereikia man populiarumo, taigi, dėkui šitam bičui už gerus straipsnius. Komentarai, kad nieko nesugebu sukurti ar parašyti pats, o tik išversti kitą darbą, taip pat not welcome.

PHP yra itin lengvai išmokstama programavimo kalba. Deja, tai nėra tik privalumas – daugelis žmonių, neturėdami visiškai jokių programavimo pagrindų, kuria PHP skriptus, kurie gali sukelti saugumo problemų. Keletas pagrindinių bėdų ir kaip jas spręsti, bus išdėstyta šiame straipsnyje.

Pirma taisyklė: Niekada nepasitikėkite savo lankytojais

Niekada niekada negalite tikėtis, kad puslapio lankytojai duos būtent tokias užklausas, kokių jūs ir tikitės. Didžiausia klaida, jei galvojate: “mano puslapyje nėra nieko įdomaus, ką galima būtų nulaužti” ir pan. Nebūtinai patyręs kompiuterio vartotojas gali tyčia bandyti padaryti žalos, tai taip pat gali atsitikti, jei jūsų programos kodas bus parašytas kreivai.
Privalote galvoti, jog bet kuris duomenų gabalėlis, gautas iš vartotojo gali būti pavojingas. Neužtenka pasitikėti vartotojo-pusės tikrinimu (client-side validation), pvz. su JavaScript, kurią galima lengvai apeiti.

Globalūs kintamieji

Daugelyje programavimo kalbų būtina kurti kintamuosius, o po to juos naudoti ar atlikti kažkokius veiksmus. PHP yra parametras, “register_globals”, kuris gali būti valdomas php.ini. Jo pagalba galite valdyti globalius kintamuosius, kuriuos nebūtina aiškiai apibrėžti.
Žvilgtelėkime į šį kodo gabalėlį:

if ($password == "my_password") {
$authorized = 1;
}
if ($authorized == 1) {
echo "Lots of important stuff.";
}

Daugeliui turbūt tai atrodo nekeliantis problemų kodas. Tačiau jei serveryje įjungti „register_globals“ ON, užtektų prie adreso eilutės prirašyti „?authorized=1“ ir turėtume priėjimą prie svarbios informacijos, kuri neturėtų būti prieinama laisvai.
Šiai problemai išspręsti yra keletas paprastų sprendimų. Geriausia yra išjungti „register_globals“ į OFF. Tada reikalingi kintamieji bus išgaunami per $_GET, $_POST, $_COOKIE, $_SESSION masyvus. Antras būdas yra įsitikinti, jog programa naudoja tik tuos kintamuosius, kuriuos ji pati nustato ir apdoroja. T.y. pastarajame pavyzdyje reiktų pridėti eilutę „$authorized=0;“ programos pradžioje.

$authorized = 0;
if ($password == "my_password") {
$authorized = 1;
}
if ($authorized == 1) {
echo "Lots of important stuff."
}

Klaidų pranešimai

Klaidų pranešimai yra naudingi ir hakeriui, ir programuotojui. Rašant kodą, jie reikalingi norint matyti kur yra klaidos ir taip jas greičiau ištaisyti. Blogiukas, pasinaudodamas klaidų pranešimais, gali gauti daug jam naudingos informacijos apie puslapį, pvz. katalogų struktūrą ar net duomenų bazės prisijungimo duomenis. Jei įmanoma, reikia išjungti klaidų pranešimus einamoje puslapio versijoje. PHP tai galima padiktuoti per .htaccess failą arba php.ini nustatant error_reporting 0 reikšmę. Galima ir pačioje kodo pradžioje įterpti tiesioginę eilutę error_reporting(0). Jei turite testavimui skirtą aplinką, ten galite nustatyti kitą klaidų pranešimų būseną, rekomenduojama, be abejo error_reporting(E_ALL).

SQL injekcija

Viena iš PHP patrauklumo priežasčių – lengvas bendravimas su duomenų bazėmis, pvz. populiari duomenų bazė MySQL. Duomenų bazės praplečia web kūrimo galimybes, suteikia didelį funkcionalumą ir t.t.
Deja, kartu su patogumu egzistuoja ir nemaži nemalonumai, su kuriais jūs galite susidurti. Laimei, yra nemažai sprendimų. Viena iš dažniausiai pasitaikančių atakų rūšių – SQL injekcija – kai vartotojas atranda saugumo spragą ir ja pasinaudodamas atlieka kenksmingas užklausas į duomenų bazę.
Imkime dažną pavyzdį – prisijungimo skriptą prie administravimo ar kitas, vartotojo prisijungimo vardo ir slaptažodžio reikalaujančias sistemas. Dažniausiai per formą paduodami vardas ir slaptažodis tikrinamas duomenų bazėje, ir jei įrašai atitinka, leidžiamas priėjimas. Štai turime tokią užklausą:

$check = mysql_query("SELECT Username, Password, UserLevel FROM Users WHERE Username = '".$_POST['username']."' and Password = '".$_POST['password']."'");

Neatrodo, kad ši užklausa galėtų sukelti pavojų, bet pabandykime įvesti į „username“ laukelį tokį tekstą:

' OR 1=1 #

Užklausa, kuri bus vykdoma, atrodys taip:

SELECT Username, Password FROM Users WHERE Username = '' OR 1=1 #' and Password = ''

Grotelės (#) pasako MySQL‘ui, kad viskas, kas eina po jo, yra komentaras ir reikia ignoruoti. Kadangi vienetas visalaik yra lygus vienetui, MySQL grąžins visus vartotojus ir slaptažodžius iš duomenų bazės. Dar blogiau, kai daugelyje sistemų pirmas vartotojas dažniausiai būna „admin“ arba „root“, taigi galime prisijungti kaip puslapio administratorius ir pridaryti nemažai žalos.
Šitai galime lengvai ištaisyti, išmesdami ar apdirbdami kai kuriuos spec. simbolius, tokiu būdu apsaugant savo užklausas. Štai toks pavyzdys:

$username = addslashes($_POST['username']);
$password = addslashes ($_POST['password']);
$check = mysql_query("SELECT Username, Password, UserLevel FROM Users WHERE Username = '".$username."' and Password = '".$password."'");

Dabar, jei vartotojas įves kenksmingus simbolius, php apdoros (escape’ins) slashus ir, jei jūsų duombazėj nėra vartotojo su neįprastu vardu - ‘\’ OR 1=1 #”, gražins tuščią rezultatą:

SELECT Username, Password, UserLevel FROM Users WHERE Username = '\' OR 1=1 #' AND Password = ''

Dabar hakeris nebegalės pridaryti jokios žalos. Svarbu tikrinti visus duomenis, siunčiamus į duomenų bazę tokiu būdu, kadangi bet kas, ką atsiunčia vartotojas gali būti suklastota. Vartotojas gali atsiųsti ir netikrus duomenis apie savo naršyklę, netikrus headerius, ir pan.

Failų manipuliacijos

Kai kurie tinklapiai turi panašias nuorodas:
index.php?page=contactus.html
index.php skriptas įterpia contactus.html failo turinį su include funkcija, ir puslapis, atrodo veikia lyg ir normaliai. Tačiau vartotojas gali labai lengvai pakeisti „contactus.html“ į bet ką, ir pavyzdžiui gali atvaizduoti .htpasswd (Apache mod_auth failas) davęs tokią užklausą:
index.php?page=.htpasswd
Vartotojas netgi gali paleisti savo sukurtą skriptą iš kito serverio. Negi nebaisu? Kad to išvengti, būtina patikrinti teisingą „open_basedir“ nuostatą php.ini faile ir išjungti „allow_url_fopen” į OFF. Taipogi būtina patikrinti užklausą, ar nurodytas failas yra leidžiamų rodyti failų sąraše.

Default reikšmių naudojimas

Suinstaliavus MySQL serverį, default vartotojas būna sukuriamas „root“ arba „sa“ su tuščiu slaptažodžiu. Jei koks nors negeras žmogus ras būdą prieiti prie duomenų bazės prisijungimo, jis būtinai išbandys šias kombinacijas. Jei šį vartotoją paliksite, ar bent nepakeisite jo slaptažodžio, vieną rytą atsibusite ir rasite švarią duomenų bazę o jūsų slapti duomenys kur nors naudojami piktiems kėslams. Analogiškai default reikšmes būtina keisti visoje programinėje įrangoje.

Instaliacijos failų palikimas serveryje

Daugelis PHP programų sukurtos su instaliacijos failais. Kai kurie jų yra save sunaikinantys, po to kai sistema instaliuojama. Kai kurios programos neleidžia dirbti, kol šie failai neištrinami. Tačiau didžioji dalis nekreipia dėmesio į instaliacijos failus, kurie visdar gali būti panaudojami, pvz. išgauti duomenų bazės prisijungimo duomenis, perrašyti duomenis arba net visą saitą iš naujo.

Nuspėjamumas

Vėlgi įsivaizduokime, kad blogiukas susidomėjo jūsų puslapiu. Jis nori įsilaužti į puslapio administravimo sistemą ir įdėti pvz. į prekių katalogą įrašą „šis saitas užknisa“. Labai tikėtina, kad jis išbandys adresą http://www.jusu_puslapis.lt/admin/ - tiesiog tam, kad įsitikintų ar jis egzistuoja. Toks kelias vėl palengvina hakerio darbą, bandant atrasti kur yra administravimo sistema. Turėdami tai omenyje, skriptus ir kitus failus, kurie gali būti pažeidžiami ar atlieka svarbius uždavinius, padėkime į sunkiai nuspėjamus katalogus. Pavyzdžiui, http://www.jusu_puslapis.lt/admin032dak3204k23/ adreso įvedimas į naršyklę užtruks ilgiau, tačiau pridės papildomo saugumo. Galima gi ir sukurti kokį šmaikštų, reikšmingą ar dar kokį originalų pavadinimą. Be to, visada galima pasinaudoti savo mėgstamos naršyklės favourites sąrašu, kai adresą galėsime pasiekti vienu-dviem pelės spragtelėjimais.
Tas pats taikytina ir vartotojo vardams bei slaptažodžiams. Nenaudokite vartotojo vardo „admin“ ar tuo labiau slaptažodžio „password“ arba „qwerty“ ar panašiai. Išsirinkite ką nors neįprasto, sudaryto iš raidžių ir skaičių kratinio ar bent kažkokios logiškos jums kombinacijos. Kai kurie hackeriai naudoja vadinamąsias žodyno atakas, bandydami visus įmanomus žodyno žodžius. Pridėję į žodį skaičių, šis būdas nueis per niek. Taipogi protinga keisti slaptažodžius reguliariai kas mėnesį ar du.

Pagaliau, įsitikinkite kad klaidų pranešimai nesuteikia jokios naudos bloga norinčiam asmeniui. Jei jūsų administravimo skriptas išmeta „blogas vartotojo vardas“, kai įvedamas neegzistuojantis vartotojo vardas, ir jei „blogas slaptažodis“ išmeta tik tada, kai netinka slaptažodis, blogiukas žinos kada jis atspėjo egzistuojantį prisijungimo vardą. Naudokite tiesiog „prisijungimo klaida“ abiems atvejams, tada vartotojas nesupras ar jis įvedė blogą slaptažodį, ar vardą, ar abu ?

Pabaiga

Visąlaik būkite paranojiški, kas liečia savo saugumą. Jei tik įsivaizduosite kiekvieną savo lankytoją kaip potencialų hakerį, jums bus lengviau gyventi. Bet kokie komentarai ir pasiūlymai laukiam medutis@medutis.com. Tikiuosi, pavyks rasti laiko ir greitu metu atsiras kitos šios serijos dalys.

Panašūs straipsniai


“PHP saugumas pirma dalis” komentarų: 7

  1. slave

    Šituos dalykus privalo žinoti visi. :-) Šaunu, kad nepatigėjai išversti.

  2. giveup

    Dekui, kaip zaliukui manau tikrai pravers :)

  3. sladex

    geras ;)

  4. Mr.Killer

    Na man labai pravertė.

    Dėkoju…

  5. GoodSoul

    Tasai sladex pasinaudojo šia informacija ir mano svetainėje ištryne 25 vartotojus (moderatorius) ir apie 50 vartotojų užbanino :D

    Bet kaip Sladex taip padarė pats supratau žiuredamas apache užklausu loga ir pasidariau nuo to apsauga.

    Praėjus dviem dienos šia svetaine radau :D žiuriu štai iš kur tas Sladex išmoko tokį dalyką :D

  6. Vaidas

    Tikrai labai gera informacija, pas man ir šios klaidos buvo paliktos. Dar norėjau paklausti ar būtina į mysal užklausas kreiptis šitaip kai čia pardoyta Username = ‘”.$username.”‘ aš kreipiuosi šitaip paprastai Username = ‘$username’ be jokių taškeliu ir dar vienų kabučių. Ar tai blogai?

  7. medutis

    tai yra sintaksės reikalas, kaip kam patogiau. Apie stringus galima čia šiek tiek pasiskaityti - gan įdomu http://blog.libssh2.org/index.php?/archives/28-How-long-is-a-piece-of-string.html

Rašyti komentarą

Jūs privalote prisijungti jeigu norite rašyti komentarą.