Trenutno stanje: PHP2Shell. Dvije kritične PHP ranjivosti (CVSS 9.2) omogućuju zlonamjerni kod bez prijave. Zakrpe od 21. 10. 2026.Što sada učiniti →

Osiguravanje sesija u PHP-u: sigurnost PHP sesija u praksi

Sesije drže korisnike prijavljenima i zato su vrijedna meta. Kako sigurno konfigurirati kolačiće, ID-ove sesija i mjesta pohrane te provesti PHP2Shell napomenu o Upload Progressu.

Stanje 5 min čitanjaSavjetnik

Ukratko: Za sigurnost PHP sesija važne su četiri stvari: sigurne postavke kolačića, novi ID sesije nakon svake prijave, odvojena i zaštićena mjesta pohrane te kratka trajanja. Zbog PHP2Shella treba na strani poslužitelja postaviti i session.upload_progress.enabled=0, sve dok nema razloga za tu funkciju.

Zašto su sesije vrijedna meta

Sesija pamti da je korisnik prijavljen. Tehnički preglednik za to dobiva nasumičan ID sesije u kolačiću, a poslužitelj pohranjuje pripadajuće podatke. Tko poznaje taj ID, za aplikaciju je isti korisnik, bez lozinke i bez drugog faktora.

Za operatere to znači: slabo upravljanje sesijama može zaobići zaštitu prijave čak i ako su lozinke i dvofaktorska prijava uredno provedeni. Osobito je to kritično kod administratorskih područja, korisničkih računa i portala s osobnim podacima.

Tipični rizici su presretanje ID-a sesije (session hijacking), podmetanje poznatog ID-a prije prijave (session fixation) i predugo važeće sesije na zajedničkim računalima.

Sigurne osnovne postavke u php.ini

Najvažnije se vrijednosti mogu središnje postaviti u php.ini ili po web-stranici u FPM poolu. U poolu koristite php_admin_value ili php_admin_flag kako aplikacija vrijednosti ne bi mogla prepisati.

; Osnovno ojačavanje sesija
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"

; PHP2Shell napomena s php.neta, zatim ponovno pokrenuti sve workere
session.upload_progress.enabled = 0

use_strict_mode osigurava da PHP ne preuzima nepoznate ID-ove koje zadaje preglednik. cookie_httponly sprječava da JavaScript pročita ID, što ograničava posljedice cross-site scriptinga. cookie_secure šalje kolačić samo preko HTTPS-a. SameSite=Lax otežava zahtjeve između stranica s važećom sesijom; za čista administratorska područja može odgovarati Strict.

Trajanje od 1800 sekundi primjer je vrijednosti. Odredite ga prema potrebi zaštite: kraće za administraciju i podatke klijenata, dulje samo gdje je to stručno nužno.

Imajte na umu da gc_maxlifetime samo određuje od kada se stari podaci sesije smiju brisati. Na nekim distribucijama datoteke sesija ne čisti sam PHP, nego redoviti sistemski posao. Provjerite tada koju vrijednost taj posao koristi kako bi Vaša postavka zaista djelovala. Za odjavu zbog neaktivnosti uz to se ne oslanjajte samo na funkciju čišćenja, nego u samoj aplikaciji provjeravajte vrijeme zadnje radnje, kako pokazuje sljedeći primjer.

Obnavljanje ID-a sesije nakon prijave

Najvažnije pravilo u kodu je ponovno generirati ID sesije pri svakoj promjeni ovlasti, dakle pri prijavi, prelasku u administratorski način i pri odjavi. Sljedeći primjer prikazuje čist osnovni obrazac s 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; // ista poruka za pogrešnu adresu i pogrešnu lozinku
    }

    session_regenerate_id(true);           // novi ID, stari odbaciti
    $_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();
}

Dopunski zaštitite obrasce koji nešto mijenjaju CSRF tokenom. Generira se s bin2hex(random_bytes(32)), pohranjuje u sesiju i pri slanju uspoređuje s hash_equals().

Mjesta pohrane i razdvajanje klijenata

PHP po zadanim postavkama sesije pohranjuje kao datoteke u zajednički direktorij. Na poslužitelju s više web-stranica to može značiti da kompromitirana web-stranica može čitati sesije druge. Zato svaka web-stranica pripada u vlastiti pool s vlastitim korisnikom i vlastitom putanjom sesija.

; u FPM poolu pripadajuće web-stranice
php_admin_value[session.save_path] = /var/lib/php/sessions/kunde-a

Direktorij bi trebao pripadati korisniku poola i imati prava 0700. Kako web-stranice dodatno međusobno odvojiti, opisuje vodič open_basedir i izolacija po web-stranici. Ako se sesije pohranjuju u Redisu ili bazi podataka, vrijede ista načela: zaseban pristup po aplikaciji, bez otvorenog mrežnog pristupa.

Sigurnost PHP sesija i PHP2Shell

PHP2Shell ranjivosti CVE-2026-109618 i CVE-2026-109619 nalaze se u samom PHP-u. Kao jednu od privremenih mjera php.net navodi postavljanje session.upload_progress.enabled=0 u php.ini, u FPM poolu ili u konfiguraciji poslužitelja i potom ponovno pokretanje svih workera. Izričito ne putem ini_set() ili .user.ini.

Dana 23.10.2026. uslijedila je obavijest o CVE-2026-115560. Moguće izvršavanje koda tamo postoji samo kod neuobičajene kombinacije serijalizacije sesija, prebacivanja putem ini_set() prije session_start() i aktivnog Upload Progressa. Zaobilazno rješenje je ista postavka, do sljedećeg redovitog izdanja s ispravcima pogrešaka.

Važno

Ova postavka je privremena mjera, a ne potpuna zaštita. Presudno ostaje ažuriranje na ispravljenu verziju PHP-a i potom ponovno pokretanje svih PHP workera.

Nakon promjene provjerite koja vrijednost zaista vrijedi. Naredbeni redak često prikazuje drugu konfiguraciju od web-poslužitelja; mjerodavna je zaštićena, potom ponovno obrisana stranica za provjeru ili sama konfiguracija poola.

Tipične pogreške sa sesijama u PHP aplikacijama

Mnoge ranjivosti ne nastaju zbog nedostajućih postavki, nego zbog načina na koji aplikacije koriste sesije. Ove obrasce ciljano provjerite u vlastitom kodu i kod pružatelja usluga:

  • Previše u sesiji: Lozinke, potpuni podaci o plaćanju ili veliki skupovi podataka ne pripadaju u sesiju. Pohranite samo ono što je nužno za dodjelu, primjerice ID korisnika i uloge.
  • Prava samo iz sesije: Tko je admin, kod kritičnih radnji treba provjeriti prema bazi podataka. Inače oduzeta prava ostaju na snazi do isteka sesije.
  • ID sesije u adresi: ID-ovi u URL-ovima završavaju u logovima, povijesti preglednika i Referer podacima. use_only_cookies i use_trans_sid = 0 to sprječavaju.
  • Nema kraja sesije: Bez timeouta zbog neaktivnosti administrator na zajedničkom računalu ostaje prijavljen neograničeno.
  • HTTPS iza proxyja pogrešno prepoznat: Ako šifriranje završava na load balanceru, aplikacija to mora znati. Inače možda postavlja kolačiće bez zastavice Secure.

Nakon sigurnosnog incidenta spada i odbacivanje svih postojećih sesija. Najjednostavnije je to učiniti brisanjem sadržaja direktorija sesija ili promjenom imena sesije. Svi se korisnici tada moraju ponovno prijaviti, a ukradene sesije postaju bezvrijedne.

Kako PHP SOS konkretno pomaže?

  • Provjeravamo postavke sesija, zastavice kolačića i mjesta pohrane na svim web-stranicama poslužitelja te dokumentiramo vrijednosti koje zaista djeluju.
  • Provodimo PHP2Shell privremene mjere po poolu, kontrolirano ponovno pokrećemo workere i dokazujemo rezultat.
  • Web-stranice razdvajamo zasebnim poolovima i putanjama sesija u okviru ojačavanja poslužitelja.
  • Kod vlastitih razvoja provjeravamo prijavu, odjavu i promjenu sesije u kodu te preporučujemo konkretne izmjene.

Česta pitanja

Što je otmica sesije (session hijacking)?

Kod otmice sesije napadač preuzima sesiju prijavljenog korisnika tako da dođe do njegova ID-a sesije. S ID-om je za aplikaciju taj korisnik, a ne zna lozinku. Sigurne zastavice kolačića i kratka trajanja to znatno otežavaju.

Zašto se ID sesije nakon prijave mora ponovno generirati?

Ako ID ostane isti prije i poslije prijave, unaprijed poznat ili podmetnut ID mogao bi i nakon prijave dalje vrijediti. session_regenerate_id(true) stvara novi ID i odbacuje stari.

Mogu li session.upload_progress.enabled isključiti putem ini_set()?

Ne, prema php.netu to nije dovoljno. Postavka pripada u php.ini, FPM pool ili konfiguraciju poslužitelja, a ne u ini_set() ili .user.ini. Nakon toga svi PHP workeri moraju se ponovno pokrenuti.

Gdje bi trebalo pohraniti datoteke sesija?

U direktoriju izvan webroota koji smije čitati samo korisnik pripadajućeg PHP poola. Na poslužiteljima s više web-stranica svaka web-stranica treba imati vlastiti direktorij sesija.

Izvori

Hitni kontakt

Svaki sat se računa. Pišite nam odmah.

Ukratko opišite sustav, verziju PHP-a i opažanje. Javit ćemo Vam se, razjasniti situaciju i raditi na daljinu dok incident nije zaključen i dokumentiran.

Hitna pomoć