Een PHP session is de meest fundamentele manier om een gebruiker over pagina's heen te onthouden, ondanks dat HTTP stateless is. Wanneer iemand inlogt, een product aan een winkelwagen toevoegt of zijn taalvoorkeur wijzigt, moet je dat ook bij het volgende verzoek weten. Sessies en cookies werken samen om dit mogelijk te maken. In dit artikel zie je stap voor stap hoe beide werken, welke instellingen ze veilig houden en hoe je je verdedigt tegen typische aanvallen zoals session fixation.
Het verschil tussen een sessie en een cookie
De twee worden vaak verward, maar hun taken verschillen. Een cookie is een klein stukje data dat in de browser wordt opgeslagen en bij elk verzoek naar de server wordt teruggestuurd. Een session is een mechanisme waarbij de data aan de serverkant leeft; de browser bewaart alleen een identifier (de session-ID) die ernaar verwijst. Dit onderscheid is belangrijk: gevoelige gegevens zoals het e-mailadres of het rechtenniveau van de gebruiker blijven op de server, en alleen een ongoksbare ID reist naar de browser.
- Cookie: in de browser, in platte tekst. De gebruiker kan het lezen en wijzigen. Geschikt voor niet-gevoelige data zoals taalvoorkeur of thema.
- Session: op de server. De gebruiker bezit alleen de ID en kan de inhoud niet zien. De juiste keuze voor authenticatie en gevoelige toestand.
Een sessie starten
Een sessie begint altijd met session_start(). Deze aanroep moet plaatsvinden voordat er output wordt verzonden — dus voor elke echo of HTML — anders krijg je de fout "headers already sent". Eenmaal gestart lees en schrijf je data via de superglobale array $_SESSION.
<?php
session_start();
// Data schrijven
$_SESSION['user_id'] = 42;
$_SESSION['locale'] = 'nl';
// Data lezen
$userId = $_SESSION['user_id'] ?? null;
Standaard wordt sessiedata opgeslagen in een bestand op de server, en de session-ID wordt naar de browser gestuurd in een cookie met de naam PHPSESSID. Er wordt dus achter de schermen al een cookie gebruikt; daarom hebben de cookie-instellingen die de session-ID beschermen direct invloed op de veiligheid ervan.
Veilige cookie-vlaggen
Een groot deel van de sessieveiligheid komt voort uit het geven van de juiste vlaggen aan de sessiecookie. Je stelt deze in met session_set_cookie_params() vóór de aanroep van session_start(). Drie vlaggen zijn cruciaal:
<?php
session_set_cookie_params([
'lifetime' => 0, // eindigt zodra de browser sluit
'path' => '/',
'secure' => true, // alleen via HTTPS
'httponly' => true, // niet bereikbaar voor JavaScript
'samesite' => 'Lax', // bescherming tegen CSRF
]);
session_start();
- Secure: de cookie wordt alleen over een HTTPS-verbinding verzonden. Dit voorkomt dat de session-ID over platte HTTP wordt gestolen.
- HttpOnly: de cookie is niet bereikbaar vanuit JavaScript via
document.cookie. Zelfs als er een XSS-lek bestaat, maakt dit het stelen van de session-ID veel moeilijker. - SameSite: bepaalt of de cookie wordt verzonden bij verzoeken die van andere sites komen.
Laxis een goede balans voor de meeste apps;Strictis strenger.
Verdedigen tegen session fixation
Een session-fixation-aanval werkt door het slachtoffer een session-ID te laten gebruiken die de aanvaller al kent. Wanneer het slachtoffer met die ID inlogt, glipt de aanvaller met dezelfde ID de sessie binnen. De oplossing is eenvoudig maar cruciaal: vernieuw de session-ID telkens wanneer het rechtenniveau verandert. Met andere woorden, roep session_regenerate_id() aan op het moment dat de gebruiker inlogt.
<?php
// NA het verifiëren van het wachtwoord
if (password_verify($password, $hash)) {
// Maak de oude sessie ongeldig, genereer een nieuwe ID
session_regenerate_id(true);
$_SESSION['user_id'] = $user['id'];
$_SESSION['logged_in'] = true;
}
Het argument true verwijdert hier ook het oude sessiebestand. Hetzelfde principe geldt bij rechtenverhoging, zoals een normale gebruiker die naar een adminpaneel overstapt.
Een sessie veilig afsluiten
Uitloggen is niet klaar met alleen het leegmaken van $_SESSION. Je moet zowel de data op de server als de cookie in de browser opruimen. Een volledige logout ziet er zo uit:
<?php
session_start();
// 1. Maak de sessiedata leeg
$_SESSION = [];
// 2. Verwijder de sessiecookie
if (ini_get('session.use_cookies')) {
$params = session_get_cookie_params();
setcookie(
session_name(), '', time() - 42000,
$params['path'], $params['domain'],
$params['secure'], $params['httponly']
);
}
// 3. Vernietig de sessie op de server
session_destroy();
Een van deze drie stappen overslaan is een veelgemaakte fout: als je alleen session_destroy() aanroept, kan er een verouderde cookie in de browser achterblijven; als je alleen $_SESSION = [] doet, wordt het bestand op de server niet verwijderd.
Je eigen cookies correct gebruiken
Naast sessies kun je cookies ook rechtstreeks gebruiken voor niet-gevoelige data zoals een taal- of themavoorkeur. Vanaf PHP 7.3 ondersteunt setcookie() het meegeven van de opties als een array, waarmee je moderne vlaggen zoals SameSite netjes kunt definiëren:
<?php
setcookie('theme', 'dark', [
'expires' => time() + 60 * 60 * 24 * 30, // 30 dagen
'path' => '/',
'secure' => true,
'httponly' => false, // als JS het moet lezen
'samesite' => 'Lax',
]);
Onthoud: data die je naar een cookie schrijft, kan door de gebruiker worden gewijzigd. Baseer dus nooit een vertrouwensbeslissing zoals "is deze gebruiker een admin?" op een cookiewaarde. Autorisatiebeslissingen moeten altijd op de sessie aan de serverkant steunen.
Veelgestelde vragen
Waar wordt sessiedata opgeslagen?
Standaard als een bestand in een tijdelijke map op de server. De instelling session.save_path bepaalt deze locatie. In apps die opschalen, is het gebruikelijk om over te stappen op een sessiedriver op basis van Redis of een database, zodat meerdere servers dezelfde sessie kunnen zien.
Hoe lang leeft een sessie?
Twee instellingen beïnvloeden dit: session.gc_maxlifetime bepaalt hoe lang de data geldig blijft op de server, terwijl de lifetime van de cookie bepaalt hoe lang de browser de session-ID bewaart. Als je een echte "uitloggen na X"-time-out wilt, is de betrouwbaarste manier om het tijdstip van laatste activiteit in de sessie op te slaan en dit zelf te controleren.
Mag ik gevoelige data in een cookie bewaren?
Nee. Een cookie staat in platte tekst in de browser en kan door de gebruiker worden gelezen en gewijzigd. Zaken als wachtwoorden of rechtenniveaus moeten in de sessie aan de serverkant blijven; een cookie mag alleen de ongoksbare session-ID of niet-gevoelige voorkeuren dragen.
Zet sessiebeheer vanaf het begin goed op. Wil je authenticatie in een bestaand PHP-project veilig maken of vanaf nul een solide sessielaag bouwen, neem dan contact met me op en laten we samen een veilige basis leggen.