Kad nesen apjautājos par to, kādas pamācības vajadzētu, tika minēti drošības principi. Kopumā pret uzbrukumiem droša php koda rakstīšana ir ļoti plaša tēma, un ja tam domā pievērsties nopietni, ar vienu rakstu būs daudz par maz, lai zinātu visu. Principā tā ir tēma, kuru vispār nav iespējams izsmelt pilnībā. Bet šeit es sākšu ar pamatiem un dažiem padomiem, kurus vajag ievērot visur un vienmēr.

 

 

1. Servera konfigurācija

Sākšu savu sarakstu ar punktu, kas uz kodu tiešā veidā nemaz neattiecas, bet pavisam tieši ietekmē drošību. Ja savu lapu liec uz publiska hostinga, tad daži no šiem punktiem tev nebūs aktuāli, bet tos derētu zināt tik un tā.

1.1. Atslēdzam PHP kļūdu paziņojumus uz produkcijas servera

(uz sava datora, vai kur nu citur Tu nodarbojies ar web lapas izstrādi gan tos noteikti vajag atstāt ieslēgtus). Kļūdu paziņojumi var dot potenciālajam uzbrucējam daudz noderīgas informācijas par serveri un pašu kodu. Lai arī slepenība nav gluži atslēga uz drošību, tomēr dažas lietas labāk paturēt apmeklētājiem neredzamas. Un šim punktam bez drošības, klāt nāk arī estētiskais faktors - lietotājiem nav jāredz mistiski kļūdu paziņojumi, kas uz viņiem neattiecas.
Kļūdu paziņojumus no apmeklētāju acīm var paslēpt konfigurācijas failā (php.ini) norādot direktīvu

display_errors 0

Vai lapas kodā

error_reporting(0);

Vēl viena laba metode šajā sakarā ir pašā lapas kodā norādīt, lai kļūdu paziņojumi rādās tikai apmeklējot lapu no atsevišķām IP adresēm (tavas adreses). Tādejādi apmeklētāji kļūdas neredzēs, bet Tu vienmēr zināsi, ka jaut kas nav kārtībā. To var panākt savas lapas index vai konfigurācijas failā ievietojot apmēram šādu kodu:

//debug konfigurācija
$dev_ips = array(
    '127.0.0.1',
    '85.31.102.92'
);

if (in_array($_SERVER['REMOTE_ADDR'], $dev_ips)) {
    ini_set('display_errors', 'On');
    error_reporting(E_ALL);
} else {
    error_reporting(0);
}

1.2. Atslēdzam register_globals

Pārliecinies, vai php.ini failā ir norādīts:

register_globals = Off

Otrs variants, kā to izslēgt - .htaccess failā:

php_flag register_globals 0

Šobrīd gan aktuālajām php versijām šis ir pēc noklusējuma izslēgts parametrs un nākotnē tiks aizvākts pavisam, tomēr der pārliecināties.

Register globals ļauj izveidot mainīgo pēc url parametra (vai post datiem utt.), tādejādi $_GET['test'] automātiski kļūst par $test.

Šī iespēja tika ieviesta, lai atvieglotu koda rakstīšanu, taču drīz vien kļuva par ievērojamu drošības draudu, ņemot vērā, ka php nav obligāti iepriekš jāinicializē mainīgos.

Tādejādi, triviālā gadījumā, ja kods izskatās šādi, lietotājam pietiktu adreses galā pierakstīt ?admin=true, lai piekļūtu administratora panelim.

if(parbaude_vai_lietotajs_ir_admins) {
    $admin = true;
}

if($admin) {
    rada_admin_paneli();
}

1.3. Izslēdzam "magic_quotes"

php.ini:

magic_quotes_gpc = Off
magic_quotes_runtime = Off
magic_quotes_sybase = Off

.htaccess:

php_flag magic_quotes_gpc 0 php_flag magic_quotes_runtime 0

Magic quotes tikai ieviests, lai atvieglotu php programmētājiem darbu ar datubāzēm un uzlabotu drošību, automātiski eskeipojot datus. Rezultāts gan ir diezgan nožēlojams, un tie rada vairāk problēmu, kā risinājumu. Par to, kā pareizi izdarīt, apskatīsiem tālākajos punktos. Šo atslēdzam. Arī šī iespēja PHP sestajā versijā tiks aizvākta, un ļoti iespējams tavā konfigurācijas failā jau būš atslēgta.

1.4 Neļauj direktoriju satura rādīšanu

Nevienam nav jāredz, kādi faili atrodas uz tava servera.

To var izdarīt (pieņemot, ka lieto apache serveri) vai nu apache konfigurācijā noņemot "Indexes", vai .htaccess failā pievienojot rindu:

Options -Indexes

Vai arī, protams, ievietojot tukšus index failus mapēs, kurās atrodas mājas lapas faili.

 

2. Viemēr pārbaudi lietotāja ievadītos datus

Lai runātu par kaut kādu drošību web lapā (vai principā, jebkurā programmā) ir jāsāk ar lietotāja ievadītas informācijas pārbaudīšanu un apstrādāšanu. Vienalga, vai tas ir skaitlis linkā, kurš nosaka kādu rakstu rādīt, meklētājā ierakstīts teksts, vai kaut vai cepuma ($_COOKIE) saturs, ja to ir iespēja izmainīt lietotājam - nekad nedrīkst paļauties uz to, ka tas nevarētu tikt aizstāds ar kādu "ļauno" kodu, vai dažos gadījumos pat nejauši saturēt simbolus, kas varētu ietekmēt lapas darbību.

2.1 Neizmanto $_GET (vai post, cookie) padotus failu nosaukumus

Nekādā gadījumā nevajag izmantot konstrukciju:

include($_GET['page'].".php");

(vai arī ko līdzīgu). Tas ļauj lapā inkludot arī failus, kuriem tur noteikti nevajadzētu atrasties un rada potenciālu drošības caurumu.

Šis ir jau daudz labāks variants:
<?php
   
switch ($_GET['page']) {
        case
"1": $inc = 'Page01.php';
        break;
        case
"2": $inc = 'Page02.php';
        break;
        case
"3": $inc = 'Page03.php';
        break;
        case
"4": $inc = 'Page04.php';
        break;
        default:
$inc = 'Page01.php';
        break;
    }
    include (
$inc);
?>

2.2. Eskeipo vai tipecast'o jebkurus datus, kas tiek iekļauti datubāzes kverijā

Lai izsargātos no SQL injekcijām, izmanto speciālu funkciju mysql_real_escape_string (vai citu DB alternatīvas, ja neizmanto MySQL), pirms iekļauj datus kverijā.

Iedomāsimies situāciju, kad tas netiek ievērots.

Mums ir kverijs

$sql = "SELECT * FROM users WHERE user='" . $_POST['user'] . "' AND password='" . $_POST['password'] . "'";

Uzbrucējam atliktu tikai ierakstīt ielogošanās formā jebkuru lietotāja vārdu un paroles laukā ' OR ''=' lai šis kverijs pārtaptu par:

SELECT * FROM users WHERE user='Admin' AND password='' OR ''=''Tā kā '' ir vienāds ar '', lietotājs veiksmīgi ielogotos kā "Admin". Tādā pašā veidā var pielikt klāt jebkuru citu SQL vaicājumu, kas būtībā nozīmē to, ka atrodot vienu šādu ievainojamību lapā, lietotājam ir pilna kontrole pār datubāzi. Un neviens neliedz izpildīt piemēram DROP table, vai nomainīt pirmās lapas raksta saturu uz "defaced by 1337 hackzjor".

Tādēļ pareizi šādam kodam būtu jāizskatās tā:

$user = mysql_real_escape_string($_POST['user']);
$password = mysql_real_escape_string($_POST['password']);

$sql = "SELECT * FROM users WHERE user='" . $user . "' AND password='" . $password . "'";

Ja padotie dati var būt tikai skaitlis, tad to var arī typecast'ot, nevis izmantot mysql_real_escape_string. Piemēram:

$id = (int) $_GET['id'];

$sql = "SELECT * FROM news WHERE id = '". $id ."'";

Nobeigumā funkcija, kas kalpo kā alternatīva mysql_real_escape_string. Sanāk īsāk rakstīt un var izmantot masīviem:

function sanitize($input) {
        if (is_array($input)) {
                foreach ($input as $k => $i) {
                        $output[$k] = sanitize($i);
                }
        } else {
                $output = mysql_real_escape_string($input);
        }
        return $output;
}

2.3. Neļauj lietotājam brīvi ievadīt HTML vai JavaScript kodu, kas pēc tam parādās lapā

Ja izvadīsi kodu, ko ierakstījis lietotājs, tas paver iespēju XSS uzbrukumiem vai vienkārši lapas izskata "salaušanai".

Izvadot tekstus izmanto htmlspecialchars() vai strip_tags() funckijas, vai arī lieto kādu no bbkoda parseriem. Ja tomēr vajag ļaut lietotājam ievadīt HTML, lielisks palīgs ir htmlpurifier, kas izfiltrēs visus "ļaunos" kodus un pie viena novērsīs kļūdas HTML kodā.

2.4. Neglabā datubāzēs paroles

Lai veiksmīgi autentificētu lietotāju, nav jābūt zināmai viņa parolei, pietiek glabāt tikai paroles hash, jeb kontrolsummu.

Kontrolsumma ir unikāla simbolu virkne, kas ir kā konkrētās paroles unikāls pirkstu nospiedums. To nav iespējams atkodēt, bet nākošreiz paroli hašojot ar to pašu algoritmu, no tās izveidosies tāds pats simbolu virknējums.

Veidojot paroļu kontrolsummas vēlams tām pievienot arī salt, jeb nejaušu simbolu virkni. Tādā gadījumā, ja paroļu kontrolsummas no datubāzes tomēr tiks nozagtas, būs daudz grūtāk tām piemeklēt īstās paroles.

$password_hash = sha1($password. 'QsDbhrYzFWPnGpaO');

Šo kontrolsummu saglabā datubāzē. Kad lietotājs mēģina ielogoties, atliek velreiz izveidot kontrolsummu no paroles, ko viņs ir ierakstījis, un salīdzināt ar kontrolsummu datubāzē.

 

3. Vispārīga piesardzība

Neatkarīgi no tā, cik ļoti tu ievērotu iepriekš minēto, un citas ar koda drošību saistītas lietas, vēl biežāks mājas lapu "uzlaušanas" iemesls, par kļūdām pašā lapas kodā, ir nesaistīts ar kodu. Viegli uzminamas paroles, vīrusi izstrādātāja datorā un novecojuši opensource skripti uz servera patiesībā ir daudz biežāks iemesls.

3.1 Paroles

Nekad neizvēlies viegli uzminamu FTP, lapas administratora vai datubāzes paroli. Neko saistītu ar projekta nosaukumu, lietotājvārdu vai e-pastu. Paroli uzminēt bieži vien ir daudz vienkāršāk, kā atrast ievainojamības nezināmā kodā.

Lieto antivīrusu programmas un neraksti ftp paroles katrā datorā, kas pagadās. Vēlams arī tās nesaglabāt FTP klientā. Ir neskaitāmi vīrusi, kas iegūst paroles no FTP klientiem un nosūta tās aaviem izstrādātājiem.

Šādā veidā iegūtās paroles parasti tiek izmantotas, lai automātiski masveidā visās iegūtajās mājas lapās saliktu linkus uz citām lapām (black hat seo), vai arī kādus "ļaunos" js kodus, kas apdraud apmeklētājus.

3.2 Open Source skripti

Ja izmanto kādu no populārajiem open source skriptiem vai cms (Joomla, Wordpress, PhpMyAdmin u.c.), vienmēr seko līdzi, lai tiem būtu jaunākās versijas un regulāri tos atjauno. Visos šajos skriptos ik pa laikam atrodas kāda ar drošību saistīta ievainojamība, kas ātri kļūst zināma cilvēkiem, kuri tās gribētu izmantot.

Arī šīs ievainojamības tiek visbiežāk izmantotas automātiski, botiem meklējot internetā lapas ar noteiktām šo programmu versijām un mēģinot izmantot tajās esošās ievainojamības. Šādi tev nezinot uz servera va ilgstoši atrasties kāda phishing lapa, un tavs domēns tikt iekļauts dažādos melnajos sarakstos.

Dažādiem administrācijas rīkiem, kā phpmyadmin vai rockmongo, ieteicams ierobežot piekļuvi tikai no konkrētām IP adresēm, ja parasti to izmanto tikai tu un tikai no sava datora. To var izdarīt vai nu ar .htaccess ierobežojot piekļuvi mapei, vai konfigurācijas failā ieliekot atļauto IP sarakstu:

//atļautās ip adreses
$dev_ips = array(
    '127.0.0.1',
    '85.31.102.92'
);

if (!in_array($_SERVER['REMOTE_ADDR'], $dev_ips)) {
    die('Pieslēgšanās no šīs IP nav atļauta!');
}

3.3 Neatstāj uz servera php info failus

Laikam šim punktam sīkāku paskaidrojumu nevajag. phpinfo sniedz pārak daudz informācijas par servera konfigurāciju, tāpēc info failus nav vēlmas turēt uz servera, kad tie nav nepieciešami.

 

Turpinājums sekos...

Laboja mad, labots 12x