Īsi: PHP sesiju drošībā svarīgas ir četras lietas: droši sīkdatņu iestatījumi, jauns sesijas ID pēc katras pieteikšanās, nodalītas un aizsargātas glabāšanas vietas un īss darbības laiks. PHP2Shell dēļ turklāt servera pusē jābūt iestatītam session.upload_progress.enabled=0, kamēr šai funkcijai nav pamata.
Kāpēc sesijas ir vērtīgs mērķis
Sesija atceras, ka lietotājs ir pieteicies. Tehniski pārlūks šim nolūkam sīkdatnē saņem nejaušu sesijas ID, un serveris saglabā attiecīgos datus. Kas pazīst šo ID, tas lietojumprogrammai ir tas pats lietotājs, bez paroles un bez otra faktora.
Operatoriem tas nozīmē: vāja sesiju pārvaldība var izslēgt pieteikšanās aizsardzību, pat ja paroles un divu faktoru autentifikācija ir tīri īstenotas. Sevišķi kritiski tas ir administrēšanas zonās, klientu kontos un portālos ar personas datiem.
Tipiskie riski ir sesijas ID nolaupīšana (Session Hijacking), zināma ID uzspiešana pirms pieteikšanās (Session Fixation) un pārāk ilgi derīgas sesijas koplietotos datoros.
Droši pamatiestatījumi php.ini
Svarīgākās vērtības var iestatīt centralizēti failā php.ini vai katrai vietnei FPM pūlā. Pūlā lietojiet php_admin_value vai php_admin_flag, lai lietojumprogramma vērtības nevarētu pārrakstīt.
; Sesiju pamatnostiprināšana
session.use_strict_mode = 1
session.use_only_cookies = 1
session.use_trans_sid = 0
session.cookie_httponly = 1
session.cookie_secure = 1
session.cookie_samesite = "Lax"
session.cookie_lifetime = 0
session.gc_maxlifetime = 1800
session.name = "APPSESSID"
; php.net PHP2Shell norāde, pēc tam pārstartēt visus darbprocesus
session.upload_progress.enabled = 0
use_strict_mode nodrošina, ka PHP nepārņem no pārlūka norādītus, nezināmus ID. cookie_httponly neļauj JavaScript nolasīt ID, kas ierobežo Cross-Site Scripting sekas. cookie_secure sūta sīkdatni tikai caur HTTPS. SameSite=Lax apgrūtina Cross-Site pieprasījumus ar derīgu sesiju; tīri administrēšanas zonām var derēt Strict.
Darbības laiks 1800 sekundes ir piemēra vērtība. Nosakiet to pēc aizsardzības vajadzības: īsāku pārvaldībai un klientu datiem, ilgāku tikai tur, kur tas profesionāli nepieciešams.
Ņemiet vērā, ka gc_maxlifetime nosaka tikai to, no kura brīža vecus sesiju datus drīkst dzēst. Dažās distribūcijās sesiju failus sakopj nevis pats PHP, bet regulārs sistēmas uzdevums. Pārbaudiet tad, kādu vērtību šis uzdevums izmanto, lai jūsu iestatījums patiešām darbotos. Atteikšanās pēc neaktivitātes gadījumā turklāt nepaļaujieties tikai uz sakopšanas funkciju, bet pašā lietojumprogrammā pārbaudiet pēdējās darbības laiku, kā parādīts nākamajā piemērā.
Sesijas ID atjaunošana pēc pieteikšanās
Svarīgākais noteikums kodā ir sesijas ID izveidot no jauna katru reizi, kad mainās tiesības, tātad pieteikšanās brīdī, pārejot administratora režīmā un atteikšanās brīdī. Turpmākais piemērs rāda tīru pamatparaugu ar password_verify():
<?php
declare(strict_types=1);
session_start();
function anmelden(PDO $db, string $email, string $passwort): bool
{
$stmt = $db->prepare('SELECT id, passwort_hash FROM benutzer WHERE email = :email');
$stmt->execute(['email' => $email]);
$nutzer = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$nutzer || !password_verify($passwort, $nutzer['passwort_hash'])) {
return false; // viens un tas pats ziņojums par nepareizu adresi un nepareizu paroli
}
session_regenerate_id(true); // jauns ID, vecais tiek atmests
$_SESSION['benutzer_id'] = (int) $nutzer['id'];
$_SESSION['letzte_aktion'] = time();
return true;
}
function pruefeLeerlauf(int $sekunden = 900): void
{
if (isset($_SESSION['letzte_aktion']) && time() - $_SESSION['letzte_aktion'] > $sekunden) {
abmelden();
return;
}
$_SESSION['letzte_aktion'] = time();
}
function abmelden(): void
{
$_SESSION = [];
$p = session_get_cookie_params();
setcookie(session_name(), '', [
'expires' => time() - 3600,
'path' => $p['path'],
'domain' => $p['domain'],
'secure' => $p['secure'],
'httponly' => $p['httponly'],
'samesite' => $p['samesite'],
]);
session_destroy();
}
Papildus veidlapas, kas kaut ko maina, aizsargājiet ar CSRF žetonu. To izveido ar bin2hex(random_bytes(32)), saglabā sesijā un nosūtot salīdzina ar hash_equals().
Glabāšanas vietas un klientu nodalīšana
Pēc noklusējuma PHP sesijas glabā kā failus kopīgā direktorijā. Serverī ar vairākām vietnēm tas var nozīmēt, ka kompromitēta vietne var nolasīt citas vietnes sesijas. Tāpēc katrai vietnei jābūt savam pūlam ar savu lietotāju un savu sesiju ceļu.
; attiecīgās vietnes FPM pūlā
php_admin_value[session.save_path] = /var/lib/php/sessions/kunde-a
Direktorijam jāpieder pūla lietotājam, un tā tiesībām jābūt 0700. Kā vietnes papildus nodalīt vienu no otras, apraksta ceļvedis open_basedir un izolācija katrai vietnei. Ja sesijas tiek glabātas Redis vai datubāzē, ir spēkā tie paši principi: sava piekļuve katrai lietojumprogrammai, nekādas atvērtas tīkla piekļuves.
PHP sesiju drošība un PHP2Shell
PHP2Shell ievainojamības CVE-2026-109618 un CVE-2026-109619 ir pašā PHP. Kā vienu no pagaidu pasākumiem php.net min session.upload_progress.enabled=0 iestatīšanu failā php.ini, FPM pūlā vai servera konfigurācijā un pēc tam visu darbprocesu pārstartēšanu. Skaidri ne caur ini_set() vai .user.ini.
- gada 23. oktobrī sekoja norāde par CVE-2026-115560. Iespējama koda izpilde tur pastāv tikai neparastas kombinācijas gadījumā: sesiju serializācija, pārslēgšana ar
ini_set()pirmssession_start()un aktīvs augšupielādes progress. Atvieglojums ir tas pats iestatījums, līdz nākamajam regulārajam kļūdu labojumu laidienam.
Šis iestatījums ir pagaidu pasākums, nevis pilnīga aizsardzība. Izšķirošs paliek atjauninājums uz izlabotu PHP versiju un tam sekojošā visu PHP darbprocesu pārstartēšana.
Pēc izmaiņas pārbaudiet, kura vērtība patiešām ir spēkā. Komandrinda bieži rāda citu konfigurāciju nekā tīmekļa serveris; pierādošs ir aizsargāts, pēc tam atkal izdzēsts pārbaudes lapas izsaukums vai pati pūla konfigurācija.
Tipiskas kļūdas ar sesijām PHP lietojumprogrammās
Daudzas ievainojamības rodas nevis trūkstošu iestatījumu dēļ, bet no tā, kā lietojumprogrammas sesijas izmanto. Šos modeļus jums mērķtiecīgi jāpārbauda savā kodā un pie pakalpojumu sniedzējiem:
- Pārāk daudz sesijā: Paroles, pilni maksājumu dati vai lieli datu kopumi sesijā nepieder. Saglabājiet tikai to, kas vajadzīgs piesaistei, piemēram, lietotāja ID un lomas.
- Tiesības tikai no sesijas: Kas ir administrators, kritiskām darbībām jāpārbauda pret datubāzi. Citādi atņemtas tiesības līdz sesijas beigām paliek spēkā.
- Sesijas ID adresē: ID URL nonāk žurnālos, pārlūka vēsturē un Referer norādēs.
use_only_cookiesunuse_trans_sid = 0to novērš. - Sesijai nav beigu: Ja nav dīkstāves taimauta, administrators koplietotā datorā paliek pieteicies neierobežoti.
- HTTPS aiz starpniekservera atpazīts nepareizi: Ja šifrēšana beidzas pie slodzes balansētāja, lietojumprogrammai tas jāzina. Citādi tā sīkdatnes var iestatīt bez
Securekarodziņa.
Pēc drošības incidenta pie tā pieder arī visu esošo sesiju atmešana. Visvienkāršāk to izdarīt, izdzēšot sesiju direktorija saturu vai nomainot sesijas nosaukumu. Visiem lietotājiem tad jāpiesakās no jauna, un nozagtas sesijas ir bezvērtīgas.
Kā PHP SOS palīdz konkrēti?
- Pārbaudām sesiju iestatījumus, sīkdatņu karodziņus un glabāšanas vietas visās servera vietnēs un dokumentējam patiešām spēkā esošās vērtības.
- PHP2Shell pagaidu pasākumus iestatām katram pūlam, kontrolēti pārstartējam darbprocesus un apliecinām rezultātu.
- Vietnes nodalām ar saviem pūliem un sesiju ceļiem servera nostiprināšanas ietvaros.
- Pašu izstrādājumiem pārbaudām pieteikšanos, atteikšanos un sesijas maiņu kodā un iesakām konkrētas izmaiņas.
Biežāk uzdotie jautājumi
Kas ir Session Hijacking?
Session Hijacking gadījumā uzbrucējs pārņem pieteikta lietotāja sesiju, iegūstot viņa sesijas ID. Ar ID viņš lietojumprogrammai ir šis lietotājs, nezinot paroli. Droši sīkdatņu karodziņi un īss darbības laiks to ievērojami apgrūtina.
Kāpēc sesijas ID pēc pieteikšanās jāizveido no jauna?
Ja ID pirms un pēc pieteikšanās paliek tas pats, iepriekš zināms vai pakaļ iegrūsts ID pēc pieteikšanās varētu turpināt darboties. session_regenerate_id(true) izveido jaunu ID un atmet veco.
Vai session.upload_progress.enabled drīkst izslēgt ar ini_set()?
Nē, saskaņā ar php.net ar to nepietiek. Iestatījums jāliek php.ini, FPM pūlā vai servera konfigurācijā, nevis ini_set() vai .user.ini. Pēc tam jāpārstartē visi PHP darbprocesi.
Kur glabāt sesiju failus?
Direktorijā ārpus webroot, ko drīkst lasīt tikai attiecīgā PHP pūla lietotājs. Serveros ar vairākām vietnēm katrai vietnei jābūt savam sesiju direktorijam.