Məzmuna keç
Educora
İrəli22 dəq9 / 10

Formalar, sessiyalar və təhlükəsizlik

$_GET və $_POST ilə forma məlumatını qəbul et, onu yoxla və htmlspecialchars ilə XSS-dən qorun, sessiya və cookie-lərlə işlə, faylları yüklə, parolları heşlə və CSRF tokenləri tətbiq et.

Özünü yoxla
Bu dərsdə öyrənəcəksən
  • Superqlobal massivlərdən forma məlumatını oxumaq, onu serverdə yoxlamaq və POST-dan sonra yönləndirmək
  • XSS-in qarşısını htmlspecialchars ilə almaq, sessiya və cookie-lərdən təhlükəsiz istifadə etmək
  • Parolları password_hash ilə saxlamaq, CSRF tokeni tətbiq etmək və yüklənən faylları yoxlamaq

Əlaqə forması, giriş səhifəsi, alış-veriş səbəti — saytın canlı hissəsi istifadəçidən gələn məlumatla işləyir. Bu məlumata isə heç vaxt kor-koranə etibar etmək olmaz: onu kimsə təsadüfən səhv, kimsə isə qəsdən zərərli yaza bilər. Bu dərsdə PHP-nin veb imkanlarını və hər veb-proqramçının bilməli olduğu əsas qorunma üsullarını öyrənəcəksən.

Superqlobal massivlər

PHP sorğu haqqında məlumatı xüsusi massivlərə yerləşdirir. Onlar kodun istənilən yerində, hətta funksiyaların içində də görünür, ona görə superqlobal adlanır. Qayda: məlumatı oxuyan sorğular (axtarış, filtr) GET ilə, məlumatı dəyişən sorğular (giriş, sifariş, şərh) isə POST ilə göndərilir.

MassivNə saxlayır
$_GETünvandakı parametrlər: search.php?q=php → $_GET['q']
$_POSTmethod="post" ilə göndərilmiş formanın sahələri
$_SERVERsorğu haqqında məlumat, məs. $_SERVER['REQUEST_METHOD']
$_COOKIE, $_SESSIONbrauzerin göndərdiyi cookie-lər və sessiya məlumatı
$_FILESyüklənmiş fayllar

XSS və htmlspecialchars

Təsəvvür et ki, qonaq kitabında kimsə adının yerinə <script> teqi yazıb. Sən onu olduğu kimi səhifəyə çıxarsan, bu skript hər ziyarətçinin brauzerində icra olunacaq: cookie-ləri oğurlaya və ya səhifəni dəyişə bilər. Bu hücum XSS (cross-site scripting) adlanır. Qorunma yolu sadədir: istifadəçidən gələn hər mətni HTML-ə çıxarmazdan əvvəl htmlspecialchars ilə ekranlaşdır.

Zəif: XSS mümkündür
<p>Hello, <?= $_GET['name'] ?>!</p>
Təhlükəsiz
<p>Hello, <?= htmlspecialchars($_GET['name'] ?? '', ENT_QUOTES, 'UTF-8') ?>!</p>
?name=<script>...</script> ünvanı ilə soldakı səhifə skripti icra edir, sağdakı isə onu adi mətn kimi göstərir.
PHP
<?php

$input = '<script>alert("hacked")</script>';
echo htmlspecialchars($input), "\n";

function e(string $value): string
{
    return htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
}

echo e("Tom & Jerry's \"show\""), "\n";
Gözlənilən nəticə
&lt;script&gt;alert(&quot;hacked&quot;)&lt;/script&gt;
Tom &amp; Jerry&#039;s &quot;show&quot;

Formanın emalı və yoxlanması

Brauzerdəki required kimi yoxlamalar yalnız rahatlıq üçündür — onları asanlıqla keçmək olar. Əsl yoxlama serverdə aparılır. Uğurlu POST-dan sonra header('Location: ...') ilə başqa səhifəyə yönləndir və exit yaz. Bu, PRG (Post/Redirect/Get) nümunəsidir: istifadəçi səhifəni yeniləyəndə forma ikinci dəfə göndərilmir.

PHP
<?php
session_start();

$errors = [];
$name = trim($_POST['name'] ?? '');
$email = trim($_POST['email'] ?? '');

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    if (mb_strlen($name) < 2) {
        $errors[] = 'Name is too short';
    }
    if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
        $errors[] = 'Email is not valid';
    }

    if ($errors === []) {
        // save the message to the database here
        $_SESSION['flash'] = "Thanks, $name!";
        header('Location: /contact.php');
        exit;
    }
}
// below: the HTML form shows $errors and refills the fields with e($name)
contact.php: formanın emalı (veb-server lazımdır)

Yoxlama üçün filter_var funksiyası rahatdır: düzgün qiymətdə onu (lazım olsa, çevrilmiş tipdə) qaytarır, səhv qiymətdə isə false verir. Onu terminalda da sınamaq olar:

PHP
<?php

var_dump(filter_var("aysel@example.com", FILTER_VALIDATE_EMAIL));
var_dump(filter_var("aysel@", FILTER_VALIDATE_EMAIL));
var_dump(filter_var("42", FILTER_VALIDATE_INT));
var_dump(filter_var("200", FILTER_VALIDATE_INT, [
    "options" => ["min_range" => 1, "max_range" => 120],
]));
Gözlənilən nəticə
string(17) "aysel@example.com"
bool(false)
int(42)
bool(false)

Sessiyalar və cookie-lər

HTTP «yaddaşsızdır»: hər sorğu əvvəlkindən xəbərsizdir. İstifadəçini tanımaq üçün iki vasitə var. Cookie brauzerdə saxlanılan kiçik məlumatdır və hər sorğu ilə serverə geri göndərilir. Sessiya isə məlumatı serverdə saxlayır, brauzerə yalnız sessiyanın identifikatoru (PHPSESSID cookie-si) verilir. session_start() və setcookie() HTTP başlıqlarını göndərir, ona görə səhifəyə hər hansı mətn çıxmazdan əvvəl çağırılmalıdır.

PHP
<?php
session_start();

$_SESSION['views'] = ($_SESSION['views'] ?? 0) + 1;

setcookie('theme', 'dark', [
    'expires' => time() + 60 * 60 * 24 * 30,
    'path' => '/',
    'httponly' => true,
    'samesite' => 'Lax',
]);

$theme = $_COOKIE['theme'] ?? 'light';
echo "Views this session: {$_SESSION['views']}, theme: $theme";
İlk açılışda: Views this session: 1, theme: light. Yenilədikdən sonra: 2, theme: dark — cookie yalnız növbəti sorğu ilə gəlir.
  • httponly cookie-ni JavaScript üçün görünməz edir — XSS olsa belə, onu oğurlamaq çətinləşir. HTTPS saytında 'secure' => true da əlavə et.
  • İstifadəçi daxil olanda session_regenerate_id(true) çağır, sonra $_SESSION['user_id'] yaz — köhnə identifikator işə yaramaz olur.
  • Çıxışda $_SESSION = []; və session_destroy(); yaz.
  • Cookie-də heç vaxt məxfi məlumat saxlama: istifadəçi onu görə və dəyişə bilər. Məxfi məlumat sessiyada qalır.

Fayl yükləmə

Fayl göndərən formada method="post" və enctype="multipart/form-data" olmalıdır. PHP faylı müvəqqəti qovluğa qoyur, məlumatını isə $_FILES-a yazır. Faylın ölçüsünü və həqiqi tipini yoxla, ona yeni təsadüfi ad ver və yalnız bundan sonra move_uploaded_file ilə köçür.

PHP
<?php

$file = $_FILES['photo'] ?? null;

if ($file && $file['error'] === UPLOAD_ERR_OK) {
    if ($file['size'] > 2 * 1024 * 1024) {
        exit('File is larger than 2 MB');
    }
    $type = mime_content_type($file['tmp_name']);
    $allowed = ['image/jpeg' => 'jpg', 'image/png' => 'png'];
    if (!isset($allowed[$type])) {
        exit('Only JPG and PNG images are allowed');
    }
    $newName = bin2hex(random_bytes(8)) . '.' . $allowed[$type];
    move_uploaded_file($file['tmp_name'], __DIR__ . '/uploads/' . $newName);
    echo 'Uploaded!';
}
upload.php: forma <input type="file" name="photo"> sahəsi göndərir

Parollar və CSRF

Parolları heç vaxt açıq şəkildə və ya md5, sha1 ilə saxlama — bu heşlər çox sürətlə sındırılır. password_hash parolu qəsdən yavaş alqoritmlə (hazırda bcrypt) və təsadüfi «duz» (salt) ilə heşləyir, password_verify isə yoxlayır. Hər çağırışda heş fərqli olur, ona görə heşləri === ilə müqayisə etmək olmaz. Bazada heş üçün VARCHAR(255) sütunu ayır.

PHP
<?php

$hash = password_hash("secret123", PASSWORD_DEFAULT);

var_dump(password_verify("secret123", $hash));
var_dump(password_verify("Secret123", $hash));
var_dump($hash === password_hash("secret123", PASSWORD_DEFAULT));
Gözlənilən nəticə
bool(true)
bool(false)
bool(false)

CSRF (cross-site request forgery) hücumunda başqa sayt istifadəçinin brauzeri adından sənin saytına forma göndərir — məsələn, onun parolunu dəyişir. Brauzer sessiya cookie-sini avtomatik əlavə etdiyi üçün sorğu «qanuni» görünür. Qorunmaq üçün sessiyada təsadüfi token yaradılır, hər POST formasına gizli sahə kimi qoyulur və gələn sorğuda yoxlanılır.

PHP
<?php
session_start();

// 1. create a token once per session
$_SESSION['csrf'] ??= bin2hex(random_bytes(32));

// 2. every POST form gets a hidden field named csrf with this value

// 3. check the token when a form is submitted
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $sent = $_POST['csrf'] ?? '';
    if (!hash_equals($_SESSION['csrf'], $sent)) {
        http_response_code(403);
        exit('Invalid CSRF token');
    }
    // the form is safe to process
}
Formada: <input type="hidden" name="csrf" value="<?= e($_SESSION['csrf']) ?>">

Əsas fikirlər

  • $_GET ünvan parametrlərini, $_POST formanın sahələrini saxlayır; məlumatı dəyişən əməliyyatlar POST ilə göndərilir.
  • İstifadəçidən gələn hər mətni HTML-ə çıxarmazdan əvvəl htmlspecialchars ilə ekranlaşdır — bu, XSS-in qarşısını alır.
  • Yoxlama serverdə aparılır (filter_var, tiplər); uğurlu POST-dan sonra header('Location: ...') və exit ilə yönləndir.
  • Sessiya məlumatı serverdə, cookie isə brauzerdə saxlanılır; session_start() hər çıxışdan əvvəl çağırılmalıdır.
  • Parollar password_hash/password_verify ilə, formalar CSRF tokeni ilə, yüklənən fayllar isə ölçü və həqiqi tip yoxlaması ilə qorunur.

Özünü yoxla

10 sual. Hər düzgün cavab XP qazandırır.

1 / 10
İstifadəçinin adını səhifəyə XSS riski olmadan çıxarmaq üçün hansı funksiya işlədilir?