- 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ı
htmlspecialcharsilə almaq, sessiya və cookie-lərdən təhlükəsiz istifadə etmək - Parolları
password_hashilə 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.
| Massiv | Nə saxlayır |
|---|---|
$_GET | ünvandakı parametrlər: search.php?q=php → $_GET['q'] |
$_POST | method="post" ilə göndərilmiş formanın sahələri |
$_SERVER | sorğu haqqında məlumat, məs. $_SERVER['REQUEST_METHOD'] |
$_COOKIE, $_SESSION | brauzerin göndərdiyi cookie-lər və sessiya məlumatı |
$_FILES | yü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.
<p>Hello, <?= $_GET['name'] ?>!</p><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
$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";<script>alert("hacked")</script> Tom & Jerry's "show"
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
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)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
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],
]));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
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";Views this session: 1, theme: light. Yenilədikdən sonra: 2, theme: dark — cookie yalnız növbəti sorğu ilə gəlir.httponlycookie-ni JavaScript üçün görünməz edir — XSS olsa belə, onu oğurlamaq çətinləşir. HTTPS saytında'secure' => trueda ə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
$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!';
}<input type="file" name="photo"> sahəsi göndərirParollar 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
$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));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
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
}<input type="hidden" name="csrf" value="<?= e($_SESSION['csrf']) ?>">Əsas fikirlər
$_GETünvan parametrlərini,$_POSTformanın sahələrini saxlayır; məlumatı dəyişən əməliyyatlarPOSTilə göndərilir.- İstifadəçidən gələn hər mətni HTML-ə çıxarmazdan əvvəl
htmlspecialcharsilə ekranlaşdır — bu, XSS-in qarşısını alır. - Yoxlama serverdə aparılır (
filter_var, tiplər); uğurluPOST-dan sonraheader('Location: ...')vəexitilə 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_verifyilə, 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.