Zastita skirpti

b0ne^
/srv/http/Posts: 22Administrator edited December 2016 in PHP

PHP Zastita skripti
Knjigu napisao: b0ne^
Greetz to: c0ax, v0da

[ Sadrzaj ]
[0] Uvod

[1] SQL Injections
[2] Local file inclusion i Remote file inclusion
[3] Local file download
[4] Cross site scripting
[5] Full path disclosure
[6] Dodatni saveti i zavrsetak

[0] Uvod
Ova mala knjiga namenjena je ljudima koji se bave PHP programiranjem i nije za apsolutne pocetnike. Necu zalaziti u objasnjavanje napada vec kako ih detektovati i spreciti. Ukoliko vas zanima hakovanjem posetite forume koji su za to namenjeni. Podrazumeva se da znate HTML i dovoljno PHP i MySQL da razumete kodove koji su ranjivi. Ukoliko imate bilo kakvih pitanja ili predloga ostavite komentar ;)

[1] SQL Injections
SQL Injections su napadi koji nastaju pri ispisu/upisu podataka iz/u bazu, Najcesce nastaju tako sto napadac za upis/ispis zada neke znakove koji prekidaju [b]mysql_query[/b] i time nastaje greska.

Evo najjednostavnijeg koda za SQL Injection prilikom ispisa. Radi se o tome da iz linka uz pomoc GETmetode uzme id i za taj id uzme text i naslov iz baze.

<?php
    include "konekcija.php"; // Uvrsavamo fajl u kome se vrsi konekcija sa bazom

    $id = $_GET['id']; // uzimamo id od novosti 
    $query = mysql_query("SELECT * FROM `novosti` WHERE `id` = '$id'") or die(mysql_error()); // uzimamo novost gde je id $id
    $num_rows = mysql_num_rows($query); // uzimamo broj upisa
    if($num_rows == 1) // proveravamo da li imamo samo jedan upis
    {
        while($row = mysql_fetch_assoc($query))
        {
            $naslov = $row['naslov']; // uzimamo naslov gde je id $id
            $text = $row['text']; // uzimamo text gde je id $id
        }
    }
?>

I sada da je link na primer http://www.link.com/novost.php?id=1 on ce uzeti novost iz baze gde je id 1. Eh sada sta bi se desilo kada bismo mi umesto tog broja jedan stavili nesto drugo, na primer aporstof (') i time cemo prekinuti mysql_query i izazvati gresku. Link bi izgledao ovako http://www.link.com/novost.php?id=1' i time obicno dobijamo sledecu gresku na stranici:

You have an error in your SQL syntax near '' at line 1.

i time kod postaje ranjiv i mogu se izvuci svi podaci iz baze a ponekad i vise od toga. Kada bi se ubacui id 1' u query to bi izgledalo ovako:

SELECT * FROM `novosti` WHERE `id` = '1''

Odakle i sami vidite da ima apostrof vise i doci ce do greske...Najbolji i najsigurniji nacin da se sprece ovi napadi jeste time sto cemo proveriti da li je id broj. Postoje dve funkcije za to a to su is_numeric i ctype_digit. Mozete koristiti bilo koju od te dve, ali je po mom misljenju ctype_digit sigurnija. Dodacemo na pocetak skripte kod za proveru i kao neku dodatnu sigurnost koja nije obavezna dodacemo i htmlspecialchars i time cemo je zastititi. Takodje cemo izbaciti i or die(mysql_error()); jer je to nepotreban deo.

<?php
    include "konekcija.php"; // Uvrsavamo fajl u kome se vrsi konekcija sa bazom

    if(!ctype_digit($_GET['id']) && $_GET['id'] != "") // proveravamo da li je $id broj
    {
        die("Pokusaj hakerskog napada!"); // ukoliko $id nije broj skripta ce se prekinuti
    }
    $id = htmlspecialchars($_GET['id'], ENT_QUOTES); // uzimamo id od novosti 
    $query = mysql_query("SELECT * FROM `novosti` WHERE `id` = '$id'"); // uzimamo novost gde je id $id
    $num_rows = mysql_num_rows($query); // uzimamo broj upisa
    if($num_rows == 1) // proveravamo da li imamo samo jedan upis
    {
        while($row = mysql_fetch_assoc($query))
        {
            $naslov = $row['naslov']; // uzimamo naslov gde je id $id
            $text = $row['text']; // uzimamo text gde je id $id
        }
    }
?>

Ovo do sada bilo je vezano za ispis iz baze, a sada cemo pogledati neke kodove vezane za upis u bazu. Recimo da imamo obicnu formu za komentare i da preko nje mozemo da ostavimo nas komentar/utisak/predlog itd.

<html>
<body>
<form method='POST'>
    Ime i prezime: <input type='text' name='imeiprezime' /><br />
    Vas komentar: <input type='text' name='komentar' /><br />
    <input type='submit' name='posalji' value='Posalji' />
</form>

<?php
    include "konekcija.php"; // Uvrsavamo fajl u kome se vrsi konekcija sa bazom
    if(isset($_POST['posalji'])) // Proveravamo da li je pritisnuto dugme submit
    {
        if(!empty($_POST['imeiprezime']) !empty(&& $_POST['komentar'])) // Proveravamo da li su zadate vrednosti za imeiprezime i komentar
        {
            $ime_i_prezime = $_POST['imeiprezime'];
            $komentar = $_POST['komentar'];
            mysql_query("INSERT INTO `komentari` (`imeiprezime`,`komentar`) VALUES ('$ime_i_prezime','$komentar')") or die(mysql_error()); // upisjemo novi komentar
        } else 
        {
            echo "Sva polja su obavezna!";
        }
    }
?>

</body>
</html>

I opet nailazimo na sledeci problem. Sta ako neko upise neki znak kao na primer apostrof(') i time izazove gresku u kodu,? Ne samo sto imamo taj problem imamo i jedan novi, a to je sta ako napadac za komentar stavi neki HTML ili JavaScript kod koji ce biti izvrsen i izazvace promene na stranici. Ovo se sprecava na jako jednostavan nacin a to je uz pomoc [b]htmlspecialchars[/b] funkcije koja ce sve specijalne karaktere kao na primer(< > ' " & i druge) pretvoriti u odredjene kodove kao na primer sto razmak postaje   i time nece moci da se izvrsi neki HTML ili JavaScript kod i nece se takodje izazvati greska prilikom upisa u bazu. Takodje cemo izbaciti i or die(mysql_error()); jer je to nepotreban deo. Evo koda koji je zasticen.

<html>
<body>
<form method='POST'>
    Ime i prezime: <input type='text' name='imeiprezime' /><br />
    Vas komentar: <input type='text' name='komentar' /><br />
    <input type='submit' name='posalji' value='Posalji' />
</form>

<?php
    include "konekcija.php"; // Uvrsavamo fajl u kome se vrsi konekcija sa bazom
    if(isset($_POST['posalji'])) // Proveravamo da li je pritisnuto dugme submit
    {
        if(!empty($_POST['imeiprezime']) !empty(&& $_POST['komentar'])) // Proveravamo da li su zadate vrednosti za imeiprezime i komentar
        {
            $ime_i_prezime = htmlspecialchars($_POST['imeiprezime'], ENT_QUOTES);
            $komentar = htmlspecialchars($_POST['komentar']), ENT_QUOTES;
            mysql_query("INSERT INTO `komentari` (`imeiprezime`,`komentar`) VALUES ('$ime_i_prezime','$komentar')"); // upisjemo novi komentar
        } else 
        {
            echo "Sva polja su obavezna!";
        }
    }
?>

</body>
</html>

Ovime smo se zastitili od SQL Injections napada i time imamo jednu brigu manje.

[2] Local file inclusion
Local file inclusion je napad koji se izvrsava kada se koristi funkcija za uvrstavanje dodatnih skripti(include, include_once, require, require_once). Najcesci primer za ovo jeste kada se uvrstavaju stranice koje se dobiju putem GET metode (http://www.link.com/index.php?strana=pocetna). Remote file inclusion je napad veoma slican Local file inclusionu samo sto se obicno uvrstava txt fajl u kome se sadrzi kod on neke skripte i taj kod se izvrsava. Evo primera za ove napade.

<?php
    $strana = $_GET['strana']; // Uzimamo vrednost 

    if(!empty($strana)) // Proveravamo da li je zadata vrednost
    {
        include $strana."php"; // Uvstavamo fajl
    }
?>

I sa ovom skriptom mozemo da uvrstimo bilo koji fajl. Necu da zalazim u detalje napada ali ako se napad LFI uspesno izvede moze da se proba drugi(Local file inclsuin to remote code execution) i time da se okaci neki fajl na sajt.

Najbolji nacin za zastitu od LFI i RFI napada jeste sledeci. Ukoliko imate 4 strane(pocetna, onama, usluge i kontakt) onda bi kod izgledao ovako i nebi mogao da se izvrsi napad.

<?php
    $strana = $_GET['strana'];
    switch($strana)
    {
        case("pocetna"):
            include "strane/pocetna.php";
        break;
        case("onama"):
            include "strane/onama.php";
        break;
        case("usluge"):
            include "strane/usluge.php";
        break;
        case("kontakt"):
            include "strane/kontakt.php";
        break;
        default:
            include "strane/pocetna.php";
        break;
    }
?>

Sada samo u slucaji da je strana jednaka necemu odredjenom uvrstavace tu stranicu, a ako nije onda ce uvrstiti pocetnu stranicu.

[3] Local file download
Recimo da imamo neku skriptu uz pomoc koje skidamo neke fajlove. Sada uz pomoc Local file download napada mozemo da probamo da skinemo fajlove koji nisu namenjeni za skidanje tipa index.php i druge skripte. Evo jedne jednostavne skripte za skidanje fajlova(necu koristi listu za mime content type jer je u ovim primerima bespotrebno).

<?php
    ob_start();
    $uploaddir = "download/";

    if($_GET['download'] != "") 
    { // Provaravmo da li je izabran fajl za skidanje
        if(file_exists($uploaddir.$_GET['download'])) 
        { // Provaravamo da li fajl postoji
            $f2d = $_GET['download'];
            $fajlc = file_get_contents($uploaddir.$f2d);
            $mime = "application/force-download";
            ob_clean();
            header("Pragma: public");
            header("Expires: 0");
            header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
            header("Cache-Control: public");
            header("Content-Description: File Transfer");
            header("Content-Type: $mime");
            header("Content-Disposition: attachment; filename=".$uploaddir.$f2d);
            header("Content-Transfer-Encoding: binary");
            header("Content-Length: " . filesize($uploaddir.$f2d));
            echo $fajlc;
            exit();
        }
    }
?>

Skripta preko GET metode uzima fajl koji ce se skidati i zapocinje preuzimanje. A sta ako napada za fajl za skidanje stavi ../index.php (../ sluzi za vracanje jednog direktorijuma nazad). Automatski ce poceti preuzimanje fajla index.php. Najlaksi nacin na koji moze da se zastiti od ovoga jeste sledeci: svi fajlovi za skidanje da budu u jednom direktorijumu i za izabran fajl da koristimo stripslashes i str_replace funkcije. Evo koda koji je zasticen.

<?php
    ob_start();
    $uploaddir = "download/";

    if(!empty($_GET['download']))
    { // Provaravmo da li je izabran fajl za skidanje
        $f2d = stripslashes(preg_replace("/\/+/", "", urldecode($_GET['download'])));
        echo $f2d;
        if(file_exists($uploaddir.$f2d)) 
        { // Provaravamo da li fajl postoji
            $fajlc = file_get_contents($uploaddir.$f2d);
            $mime = "application/force-download";
            ob_clean();
            header("Pragma: public");
            header("Expires: 0");
            header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
            header("Cache-Control: public");
            header("Content-Description: File Transfer");
            header("Content-Type: $mime");
            header("Content-Disposition: attachment; filename=".$uploaddir.$f2d);
            header("Content-Transfer-Encoding: binary");
            header("Content-Length: " . filesize($uploaddir.$f2d));
            echo $fajlc;
            exit();
        }
    }
?>

I ovime nece moci da se preuzime nijedan fajla van zadatog direktorijuma.

[4] Cross site scripting
Cross site scripting je vrsta hakerskog napada. Izvrsava se kada imamo formu i kada dajemo vrednost necemu i kasnije se ta vrednost ispisuje. Mozemo da probamo Cross site scripting napad i da izvrsimo neki JavaScript kod. Na primer ukoliko je u pitanju forma za pretragu i neko zada umesto teksta za pretrazivanje neki JavaScript kod (alert("xss")) kad god se stranica ocita taj kod ce biti izvrsen kao JavaScript kod i iskocice mali prozor u kome ce pisati xss. Evo ranjive skripte na ovu vrstu napada.

<html>
<body>
<form method='POST'>
   Search: <input type='search' name='search' /><br />
   <input type='submit' name='posalji' value='Posalji' />
</form>

<?php
    if(isset($_POST['posalji'])) // Proveravamo da li je pritisnuto dugme submit
    {
       if($_POST['search'] != "") // Proveravamo da li su zadate vrednosti za pretragu
       {
          $search = $_POST['search'];
          echo $search;
          // ovde ide kod za pretragu koji necemo pisati jer nije potreban u ovom primeru
       } else 
       {
          echo "Sva polja su obavezna!";
       }
    }
?>

</body>
</html>

I kao sto sam malopre rekao kada bi neko upisao alert("xss") iskocio bi prozor u kome bi pisalo xss. Sa ovim napadom moze se izvrsiti cak i kradaja cooki-a i druge stvari ali to je nebitno zato sto je zastita od svega toga na jedan isti nacin, tj koriscenjem funkcije htmlspecialchars. Evo zasticenog koda.

<html>
<body>
<form method='POST'>
   Search: <input type='search' name='search' /><br />
   <input type='submit' name='posalji' value='Posalji' />
</form>

<?php
    if(isset($_POST['posalji'])) // Proveravamo da li je pritisnuto dugme submit
    {
       if($_POST['search'] != "") // Proveravamo da li su zadate vrednosti za pretragu
       {
          $search = htmlspecialchars($_POST['search']);
          echo $search;
          // ovde ide kod za pretragu koji necemo pisati jer nije potreban u ovom primeru
       } else 
       {
          echo "Sva polja su obavezna!";
       }
    }
?>

</body>
</html>

I sada ce na stranici bukvalno biti ispisano ono sto se zada za pretragu i nece se izvrsavati kao HTML ili JavaScript kod ili nesto trece.

[5] Full path disclosure
Full path disclosure je neka vrsta napada koji nam pomaze kako bismo dobili vise informacija o sajtu, i pokusati da izvrsimo neki drugi napad, tako sto cemo izazvati gresku i procitati je. Napad se najcesce izvrsava tako sto se kod GET metode doda [] pre = (http://www.link.com/index.php?strana[]=pocetna). Najbolji nacin za zastitu od ovoga jeste da se na pocetak same skripte doda error_reporting(0) cime cemo namestiti da se greske ne prikazuju. Zasticen kod bi izgledao ovako.

<?php
    error_reporting(0);

    // dalje ide vas kod za sta god on bio

?>

[6] Dodatni saveti i zavrsetak
Evo par licnih saveta koji vam mogu pomoci kod osigravanja skripti. Uvek kod formi proverite svaku varijablu(npr za email da li je validna email adresa tipa email@gmail.com a ne adpasdpasdhapsd) ili da li je duzina upisanog imena predugacka i tako dalje. Ukoliko negde ne proverite varijablu moze doci do toga da se neko rodio 1. 1. 1337. ili da korisnik za email unese nevalidnu email adresu ili predugacko ime i tim izazove gresku prilikom upisa u bazu. To bi bilo to od mene. Nadam se da sam vam pomogao i da ste naucili nesto novo sto se tice sigurnosti PHP programiranja.

Ukoliko kopirate tutorial ostavite creditz. Pozdrav ;)

If you don't know who I am, then maybe your best course would be to tread lightly.

Sign In or Register to comment.

Welcome

It looks like you're new here. If you want to get involved, click one of these buttons!

Discussions