Sessions en authentication in PHP uitgelegd

Leer hoe sessions en authentication in PHP werken. Praktische uitleg over login, sessiebeheer, cookies en security voor developers in 2026.

14 juni 20267 min leestijdDoor We Develop Communication

Een goede implementatie van sessions en authentication in PHP is het verschil tussen een veilige applicatie en een datalek dat de voorpagina haalt. Toch zien we in de praktijk nog vaak dat ontwikkelaars sessiebeheer onderschatten of bouwen op verouderde voorbeelden uit oude tutorials.

In dit artikel leer je hoe sessions in PHP werken, hoe je een veilig loginsysteem bouwt en welke valkuilen je moet vermijden. We behandelen zowel de basis als de belangrijkste securitymaatregelen die in 2026 de standaard zijn.

De voorbeelden bouwen voort op eerdere artikelen uit deze serie, zoals werken met databases via PDO en validatie en security basics. Heb je die nog niet gelezen, doe dat dan eerst.

Wat is een session in PHP?

Een session is een manier om data te onthouden tussen verschillende requests van dezelfde gebruiker. HTTP is van nature stateless: elke request staat los van de vorige. Zonder sessions zou je gebruiker bij elke pagina opnieuw moeten inloggen.

PHP lost dit op door een uniek session-ID te genereren, dit in een cookie op te slaan en de bijbehorende data op de server te bewaren. Bij elke volgende request stuurt de browser het session-ID mee, waarna PHP de juiste sessiedata terughaalt.

De sessiedata zelf staat dus nooit in de browser. Alleen de sleutel (het session-ID) reist heen en weer. Dat maakt sessions veiliger dan puur cookies voor gevoelige informatie zoals een ingelogde userstatus.

Sessions versus cookies

Cookies worden volledig aan de client-kant opgeslagen. Alles wat je erin zet, kan de gebruiker (of een aanvaller) lezen en aanpassen. Voor niet-gevoelige data zoals een taalvoorkeur is dat prima.

Sessions zijn de juiste keuze voor alles wat vertrouwelijk of security-gerelateerd is: user-ID's, rollen, winkelwagens, CSRF-tokens. De server houdt de waarheid vast, de client heeft alleen een ondoorzichtige verwijzing.

Een session starten en gebruiken

Het startpunt is altijd de functie session_start(). Deze moet worden aangeroepen voordat er output naar de browser wordt gestuurd, anders krijg je een headers already sent-error.

<?php
session_start();

$_SESSION['user_id'] = 42;
$_SESSION['username'] = 'sander';

echo "Welkom, " . htmlspecialchars($_SESSION['username']);

De superglobal $_SESSION gedraagt zich als een normale associatieve array. Alles wat je erin zet, is beschikbaar in alle andere scripts waar je session_start() aanroept, zolang de sessie geldig is.

Voor een complete uitleg over arrays kun je ons artikel arrays en loops in PHP raadplegen. Sessies werken met dezelfde syntax, alleen is de data persistent.

Een sessie beëindigen

Uitloggen is méér dan alleen $_SESSION leeggooien. Je moet ook de sessiecookie verwijderen en de sessiedata op de server vernietigen.

<?php
session_start();

$_SESSION = [];

if (ini_get('session.use_cookies')) {
    $params = session_get_cookie_params();
    setcookie(
        session_name(),
        '',
        time() - 42000,
        $params['path'],
        $params['domain'],
        $params['secure'],
        $params['httponly']
    );
}

session_destroy();
header('Location: /login');
exit;

Dit zorgt ervoor dat er geen restjes blijven hangen die een aanvaller kan misbruiken.

Authentication: een loginsysteem bouwen

Authentication draait om één simpele vraag: "Is deze gebruiker wie hij beweert te zijn?" In PHP bouw je dat meestal met een combinatie van een formulier, een database en sessiebeheer.

Wachtwoorden veilig opslaan

Sla nooit wachtwoorden op als plain text. Gebruik ook geen MD5 of SHA1, die zijn al jaren niet meer veilig. PHP biedt sinds versie 5.5 de functies password_hash() en password_verify() die het goede algoritme voor je kiezen.

<?php
$password = $_POST['password'];
$hash = password_hash($password, PASSWORD_DEFAULT);

$pdo->prepare('INSERT INTO users (email, password_hash) VALUES (?, ?)')
    ->execute([$_POST['email'], $hash]);

PASSWORD_DEFAULT kiest automatisch het sterkste algoritme dat PHP op dat moment ondersteunt. In 2026 is dat Argon2id of bcrypt. Omdat de hash een versie-indicator bevat, blijven oude hashes werken wanneer PHP later upgradet.

Inloggen verifiëren

Bij het inloggen haal je de hash op en controleer je die met password_verify():

<?php
session_start();

$stmt = $pdo->prepare('SELECT id, password_hash FROM users WHERE email = ?');
$stmt->execute([$_POST['email']]);
$user = $stmt->fetch();

if ($user && password_verify($_POST['password'], $user['password_hash'])) {
    session_regenerate_id(true);
    $_SESSION['user_id'] = $user['id'];
    header('Location: /dashboard');
    exit;
}

echo "Ongeldige inloggegevens";

Merk op dat we bij een mislukte login niet zeggen of het e-mailadres of het wachtwoord fout was. Dat voorkomt dat aanvallers geldige e-mailadressen kunnen achterhalen.

Waarom session_regenerate_id() cruciaal is

Direct na een succesvolle login roep je session_regenerate_id(true) aan. Dit genereert een nieuw session-ID en verwijdert de oude. Hiermee voorkom je session fixation-aanvallen, waarbij een aanvaller een slachtoffer een bekend session-ID toeschuift voordat deze inlogt.

Authenticatie beschermen: security best practices

Een werkend loginscherm is het begin, niet het einde. De echte uitdaging zit in het afschermen tegen misbruik.

Configureer je sessiecookies altijd met de juiste flags. Dit doe je in php.ini of runtime via session_set_cookie_params():

<?php
session_set_cookie_params([
    'lifetime' => 0,
    'path' => '/',
    'domain' => '',
    'secure' => true,
    'httponly' => true,
    'samesite' => 'Lax',
]);
session_start();
  • secure: cookie wordt alleen over HTTPS verstuurd
  • httponly: JavaScript kan de cookie niet lezen (bescherming tegen XSS)
  • samesite: beperkt cross-site requests (bescherming tegen CSRF)

Brute force voorkomen

Een inlogformulier zonder ratelimiting is een open uitnodiging. Houd het aantal mislukte pogingen per IP of per account bij en blokkeer tijdelijk na bijvoorbeeld vijf mislukte pogingen.

Dit kun je zelf implementeren in de database, of via middleware. Zie ons artikel over middleware en routing voor hoe je dit elegant aanpakt.

Session timeout

Laat sessies niet oneindig lang leven. Voor de meeste applicaties is een timeout van 30 minuten inactiviteit een redelijk uitgangspunt.

<?php
session_start();

$timeout = 1800;

if (isset($_SESSION['last_activity']) && time() - $_SESSION['last_activity'] > $timeout) {
    session_unset();
    session_destroy();
    header('Location: /login?reason=timeout');
    exit;
}

$_SESSION['last_activity'] = time();

Authentication in een framework

Alles wat we tot nu toe hebben gezien, kun je handmatig bouwen. Maar in de praktijk gebruiken de meeste moderne PHP-projecten een framework dat dit voor je regelt.

Laravel bijvoorbeeld biedt out-of-the-box een authentication-scaffold met hashing, session-management, rate limiting en remember-me-functionaliteit. Symfony heeft een vergelijkbare security-component.

Het voordeel: minder kans op fouten en een door de community geteste implementatie. Het nadeel: je moet vertrouwen op abstracties die niet altijd transparant zijn. De concepten uit dit artikel helpen je wél begrijpen wat er onder de motorkap gebeurt.

Voor meer context over hoe frameworks deze logica structureren, lees ook het MVC pattern in PHP.

Stateless authentication: API tokens en JWT

Voor API's werkt sessiebeheer vaak onhandig. Een stateless aanpak met tokens is dan beter. Een client stuurt bij elke request een token mee in de Authorization-header, en de server valideert dat token zonder sessiestate.

JSON Web Tokens (JWT) zijn hier de populairste keuze. Een JWT bevat ingebakken data (zoals user-ID en expiratie) en is cryptografisch ondertekend. In ons artikel over een API bouwen in PHP gaan we hier dieper op in.

Let op: JWT's zijn niet automatisch veiliger dan sessies. Ze hebben eigen valkuilen, zoals lastige revocation en het risico op lange levensduur wanneer tokens gelekt worden.

Veelvoorkomende fouten

Een paar patronen zien we in code reviews steeds terugkomen:

  • Session-ID in URL's plaatsen, gebruik altijd cookies, nooit de query string
  • Gevoelige data in sessies zonder encryptie bij shared hosting, controleer waar sessiebestanden staan
  • Vergeten session_regenerate_id() aan te roepen na privilegewijziging, niet alleen bij login, ook bij wachtwoordwijziging
  • Geen CSRF-token bij state-changing forms, sessions alleen zijn niet genoeg
  • Inlognamen loggen in error logs, onbedoeld lek van user-data

De OWASP Session Management Cheat Sheet is een uitstekende referentie voor verdere verdieping.

Veelgestelde vragen

Een cookie is data die in de browser van de gebruiker wordt opgeslagen. Een session slaat data op de server op en gebruikt alleen een cookie met het session-ID om gebruikers te herkennen. Sessions zijn daardoor veiliger voor gevoelige data.

Hoe start je een session in PHP?

Je roept session_start() aan bovenaan je script, voordat je iets naar de output stuurt. Daarna kun je data opslaan in de superglobal $_SESSION en die bij elke request weer uitlezen.

Hoe sla je een wachtwoord veilig op in PHP?

Gebruik password_hash() om wachtwoorden te hashen met bcrypt of Argon2 voordat je ze opslaat. Controleer ingevoerde wachtwoorden met password_verify(). Sla nooit wachtwoorden op in plain text of met MD5/SHA1.

Wat is session hijacking en hoe voorkom je het?

Session hijacking is het stelen van een session-ID om de identiteit van een gebruiker over te nemen. Je voorkomt het door HTTPS te gebruiken, httpOnly en secure cookies in te stellen en session_regenerate_id() aan te roepen na login.

Moet ik JWT of sessions gebruiken voor authentication?

Voor traditionele webapplicaties zijn server-side sessions meestal de simpelste en veiligste keuze. JWT is handiger voor stateless API's of microservices waar meerdere servers hetzelfde token moeten valideren zonder centrale sessiestore.

Conclusie

Sessions en authentication in PHP zijn geen rocket science, maar de details bepalen of je applicatie veilig is. Gebruik password_hash() voor wachtwoorden, session_regenerate_id() na login, en zet altijd de juiste cookie flags.

Of je nu handmatig bouwt of een framework gebruikt, begrijp wat er onder de motorkap gebeurt. Dat voorkomt dat een lek ontstaat op precies die plek waar je een abstractie blindelings vertrouwde.

Veelgestelde vragen

Klaar om digitaal te groeien?

Wij helpen Nederlandse bedrijven met webtechnologie en SEO-strategieën die écht werken. Neem vrijblijvend contact op.