Trumpai: PHP sesijų saugai svarbūs keturi dalykai: saugūs slapukų nustatymai, naujas sesijos ID po kiekvieno prisijungimo, atskiros ir apsaugotos saugojimo vietos bei trumpa galiojimo trukmė. Dėl PHP2Shell be to serverio pusėje turėtų būti nustatyta session.upload_progress.enabled=0, jei šios funkcijos nereikia.
Kodėl sesijos yra vertingas taikinys
Sesija įsimena, kad naudotojas prisijungęs. Technine prasme naršyklė tam slapuke gauna atsitiktinį sesijos ID, o serveris išsaugo susijusius duomenis. Kas žino šį ID, programai yra tas pats naudotojas, be slaptažodžio ir be antro veiksnio.
Operatoriams tai reiškia: silpnas sesijų valdymas gali apeiti prisijungimo apsaugą, net jei slaptažodžiai ir dviejų veiksnių autentifikacija įgyvendinti tvarkingai. Ypač kritiška tai administravimo srityse, klientų paskyrose ir portaluose su asmens duomenimis.
Tipinės rizikos yra sesijos ID pagrobimas (session hijacking), žinomo ID pakišimas prieš prisijungimą (session fixation) ir per ilgai galiojančios sesijos bendrai naudojamuose kompiuteriuose.
Saugūs pagrindiniai php.ini nustatymai
Svarbiausias reikšmes galima nustatyti centralizuotai php.ini arba kiekvienai svetainei FPM baseine. Baseine naudokite php_admin_value arba php_admin_flag, kad programa reikšmių negalėtų perrašyti.
; Pagrindinis sesijų sutvirtinimas
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 pastaba dėl PHP2Shell, po to iš naujo paleisti visus darbinius procesus
session.upload_progress.enabled = 0
use_strict_mode užtikrina, kad PHP nepriimtų naršyklės nurodytų nežinomų ID. cookie_httponly neleidžia JavaScript perskaityti ID, o tai riboja Cross-Site Scripting pasekmes. cookie_secure siunčia slapuką tik per HTTPS. SameSite=Lax apsunkina Cross-Site užklausas su galiojančia sesija; grynoms administravimo sritims gali tikti Strict.
1800 sekundžių trukmė yra pavyzdinė reikšmė. Nustatykite ją pagal apsaugos poreikį: trumpesnę administravimui ir klientų duomenims, ilgesnę tik ten, kur to reikia pagal paskirtį.
Atkreipkite dėmesį, kad gc_maxlifetime tik nustato, nuo kada senus sesijos duomenis leidžiama ištrinti. Kai kuriose distribucijose sesijos failus tvarko ne pats PHP, o reguliari sistemos užduotis. Tuomet patikrinkite, kokią reikšmę ši užduotis naudoja, kad jūsų nustatymas iš tikrųjų veiktų. Atjungimu dėl neveiklumo taip pat nepasikliaukite vien valymo funkcija, o paskutinio veiksmo laiką tikrinkite pačioje programoje, kaip parodyta kitame pavyzdyje.
Sesijos ID atnaujinimas po prisijungimo
Svarbiausia taisyklė kode yra sesijos ID sukurti iš naujo kiekvieną kartą, kai keičiasi teisės, t. y. prisijungiant, pereinant į administratoriaus režimą ir atsijungiant. Toliau pateiktas pavyzdys rodo tvarkingą pagrindinį šabloną su 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; // tas pats pranešimas esant klaidingam adresui ir slaptažodžiui
}
session_regenerate_id(true); // naujas ID, senas atmetamas
$_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();
}
Papildomai formas, kurios ką nors keičia, apsaugokite CSRF žetonu. Jis sukuriamas su bin2hex(random_bytes(32)), išsaugomas sesijoje ir pateikiant lyginamas su hash_equals().
Saugojimo vietos ir klientų atskyrimas
Pagal numatymą PHP sesijas saugo kaip failus bendrame kataloge. Serveryje su keliomis svetainėmis tai gali reikšti, kad kompromituota svetainė gali skaityti kitos sesijas. Todėl kiekvienai svetainei priklauso savas baseinas su savu naudotoju ir savu sesijų keliu.
; atitinkamos svetainės FPM baseine
php_admin_value[session.save_path] = /var/lib/php/sessions/kunde-a
Katalogas turėtų priklausyti baseino naudotojui ir turėti teises 0700. Kaip svetaines papildomai atskirti viena nuo kitos, aprašo vadovas open_basedir ir izoliacija kiekvienai svetainei. Jei sesijos saugomos Redis ar duomenų bazėje, galioja tie patys principai: sava prieiga kiekvienai programai, jokios atviros tinklo prieigos.
PHP sesijų sauga ir PHP2Shell
PHP2Shell pažeidžiamumai CVE-2026-109618 ir CVE-2026-109619 yra pačiame PHP. Kaip vieną iš pereinamųjų priemonių php.net nurodo session.upload_progress.enabled=0 nustatymą php.ini, FPM baseine ar serverio konfigūracijoje ir po to visų darbinių procesų paleidimą iš naujo. Aiškiai ne per ini_set() ar .user.ini.
2026-10-23 sekė pranešimas apie CVE-2026-115560. Galimas kodo vykdymas ten kyla tik esant neįprastam sesijų serializacijos, perjungimo per ini_set() prieš session_start() ir aktyvaus upload progress deriniui. Pagalba yra tas pats nustatymas iki kito įprasto klaidų taisymo leidimo.
Šis nustatymas yra pereinamoji priemonė, o ne visiška apsauga. Lemiamas lieka atnaujinimas į ištaisytą PHP versiją ir po to visų PHP darbinių procesų paleidimas iš naujo.
Po pakeitimo patikrinkite, kuri reikšmė iš tikrųjų galioja. Komandinė eilutė dažnai rodo kitokią konfigūraciją nei žiniatinklio serveris; patikimas yra apsaugotas, po to vėl ištrintas patikros puslapis arba pati baseino konfigūracija.
Tipinės sesijų klaidos PHP programose
Daug pažeidžiamumų atsiranda ne dėl trūkstamų nustatymų, o dėl to, kaip programos sesijas naudoja. Šiuos šablonus savo kode ir pas paslaugų teikėjus klauskite tikslingai:
- Per daug sesijoje: slaptažodžiai, pilni mokėjimo duomenys ar dideli duomenų rinkiniai sesijoje nepriklauso. Saugokite tik tai, ko reikia priskyrimui, pavyzdžiui, naudotojo ID ir roles.
- Teisės tik iš sesijos: ar asmuo administratorius, kritinių veiksmų metu turėtų būti tikrinama pagal duomenų bazę. Kitaip atimtos teisės galioja iki sesijos pabaigos.
- Sesijos ID adrese: ID URL patenka į žurnalus, naršyklės istoriją ir Referer nuorodas.
use_only_cookiesiruse_trans_sid = 0to neleidžia. - Sesija be pabaigos: be neveiklumo laiko limito administratorius bendrame kompiuteryje lieka prisijungęs neribotai.
- HTTPS už tarpinio serverio atpažįstamas klaidingai: jei šifravimas baigiasi apkrovos balansuotoju, programa tai turi žinoti. Kitaip ji gali nustatyti slapukus be
Securevėliavėlės.
Po saugumo incidento taip pat reikia atmesti visas esamas sesijas. Paprasčiausia tai padaryti ištrynus sesijų katalogo turinį arba pakeitus sesijos pavadinimą. Visi naudotojai tuomet turi prisijungti iš naujo, o pavogtos sesijos tampa bevertės.
Kaip PHP SOS padeda konkrečiai?
- Tikriname sesijų nustatymus, slapukų vėliavėles ir saugojimo vietas visose serverio svetainėse ir dokumentuojame iš tikrųjų veikiančias reikšmes.
- PHP2Shell pereinamąsias priemones įgyvendiname kiekviename baseine, kontroliuojamai iš naujo paleidžiame darbinius procesus ir įrodome rezultatą.
- Svetaines atskiriame savais baseinais ir sesijų keliais pagal serverio sutvirtinimą.
- Nuosavoms kūrimo sistemoms kode tikriname prisijungimą, atsijungimą ir sesijų keitimą ir rekomenduojame konkrečius pakeitimus.
Dažni klausimai
Kas yra sesijos pagrobimas (session hijacking)?
Sesijos pagrobimo metu užpuolikas perima prisijungusio naudotojo sesiją, gavęs jo sesijos ID. Su ID jis programai yra tas naudotojas, nežinodamas slaptažodžio. Saugios slapukų vėliavėlės ir trumpa galiojimo trukmė tai gerokai apsunkina.
Kodėl sesijos ID reikia sukurti iš naujo po prisijungimo?
Jei ID prieš prisijungimą ir po jo vienodas, anksčiau žinomas ar pakištas ID po prisijungimo galėtų toliau galioti. session_regenerate_id(true) sukuria naują ID ir atmeta seną.
Ar session.upload_progress.enabled galiu išjungti per ini_set()?
Ne, pagal php.net to nepakanka. Nustatymas priklauso php.ini, FPM baseinui ar serverio konfigūracijai, o ne ini_set() ar .user.ini. Po to reikia iš naujo paleisti visus PHP darbinius procesus.
Kur turėtų būti saugomi sesijų failai?
Kataloge už žiniatinklio šaknies ribų, kurį gali skaityti tik atitinkamo PHP baseino naudotojas. Serveriuose su keliomis svetainėmis kiekviena svetainė turėtų turėti savo sesijų katalogą.