Proteggere gli endpoint PHP con autenticazione basata su token

by theArchitect
SHARE
Proteggere gli endpoint PHP con autenticazione basata su token
© Guida-HTML5.it

Introduzione

Quando si parla di sicurezza in PHP, spesso si pensa subito a SQL injection, XSS o gestione delle password. Un aspetto molto pratico, però, è la protezione degli endpoint: cioè tutte quelle pagine o API che devono essere accessibili solo da utenti autorizzati.

Un errore comune è affidarsi a controlli deboli, come un semplice parametro nell’URL o una variabile di sessione gestita male. In un’applicazione reale, soprattutto quando si costruiscono pannelli admin, servizi interni, webhook o endpoint AJAX, è molto più robusto usare un token di autenticazione da inviare nelle richieste HTTP.

In questo tutorial vedremo un approccio semplice ma efficace: autenticazione basata su token Bearer. È una soluzione utile per proteggere endpoint PHP in modo chiaro, scalabile e adatta anche a integrazioni con frontend separati o client esterni.

L’obiettivo non è costruire un sistema di login completo, ma capire come difendere un endpoint PHP verificando un token valido prima di eseguire operazioni sensibili.

Codice completo

Nel seguente esempio simuliamo un piccolo endpoint PHP che restituisce dati riservati solo se il client invia un token corretto nell’header Authorization.

<?php
declare(strict_types=1);

/**
 * Esempio di protezione endpoint con token Bearer.
 * In un progetto reale, il token andrebbe letto da database o configurazione sicura.
 */

// Token atteso: in produzione non hardcodarlo nel codice.
const API_TOKEN = ´c9f1f0b7e8f44c2d9a1e7b3f6a8d1234´;

header(´Content-Type: application/json; charset=utf-8´);

/**
 * Legge l´header Authorization in modo compatibile.
 */
function getAuthorizationHeader(): ?string
{
    $headers = function_exists(´getallheaders´) ? getallheaders() : [];

    foreach ($headers as $name => $value) {
        if (strtolower($name) === ´authorization´) {
            return trim($value);
        }
    }

    return $_SERVER[´HTTP_AUTHORIZATION´] ?? $_SERVER[´REDIRECT_HTTP_AUTHORIZATION´] ?? null;
}

/**
 * Estrae il token dal formato: "Bearer <token>"
 */
function extractBearerToken(?string $authorizationHeader): ?string
{
    if ($authorizationHeader === null) {
        return null;
    }

    if (preg_match(´/^Bearers+(.+)$/i´, $authorizationHeader, $matches)) {
        return trim($matches[1]);
    }

    return null;
}

/**
 * Invia una risposta JSON di errore e termina lo script.
 */
function denyAccess(string $message, int $statusCode = 401): void
{
    http_response_code($statusCode);

    echo json_encode([
        ´success´ => false,
        ´error´ => $message
    ], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);

    exit;
}

// 1) Leggiamo l´header Authorization
$authorizationHeader = getAuthorizationHeader();

// 2) Estraiamo il token Bearer
$token = extractBearerToken($authorizationHeader);

// 3) Verifica del token
if ($token === null) {
    denyAccess(´Token mancante. Usa l’header Authorization: Bearer <token>´, 401);
}

if (!hash_equals(API_TOKEN, $token)) {
    denyAccess(´Token non valido.´, 403);
}

// 4) Se il token è corretto, eseguiamo la logica protetta
$response = [
    ´success´ => true,
    ´message´ => ´Accesso autorizzato.´,
    ´data´ => [
        ´report´ => ´Dati riservati visibili solo agli utenti autenticati.´,
        ´generated_at´ => date(´c´)
    ]
];

echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);

Spiegazione

Vediamo il codice pezzo per pezzo, così da capire non solo cosa fa, ma anche perché è utile.

1. Header Authorization

Il client invia il token nell’header HTTP:

Authorization: Bearer c9f1f0b7e8f44c2d9a1e7b3f6a8d1234

Questa modalità è molto diffusa perché separa bene l’autenticazione dal contenuto della richiesta. È più pulita rispetto a passare token in query string, soluzione da evitare perché può lasciare tracce nei log, nella cronologia del browser o nei referrer.

2. Estrazione del token

La funzione extractBearerToken() controlla che il formato sia corretto e recupera solo la parte del token. Questo evita di lavorare con stringhe malformate e rende il codice più robusto.

3. Confronto sicuro

Per verificare il token usiamo hash_equals(). Questo dettaglio è importante: il confronto diretto con == o === può esporre a timing attack in contesti sensibili. hash_equals() effettua un confronto più adatto alla sicurezza.

4. Risposte HTTP corrette

Se il token manca, restituiamo 401 Unauthorized. Se il token è presente ma errato, usiamo 403 Forbidden. Questa distinzione è utile perché comunica chiaramente il motivo del fallimento e aiuta anche nel debug lato client.

5. Separazione tra autenticazione e logica

Prima controlliamo l’accesso, poi eseguiamo la logica protetta. È un principio fondamentale: non mescolare validazione e business logic. In questo modo il codice resta più leggibile e più facile da mantenere.

Best practice

Proteggere un endpoint con token è utile, ma va fatto nel modo giusto. Ecco alcune buone pratiche da seguire in progetti PHP reali.

  • Non hardcodare i token nel codice: salva i segreti in variabili d’ambiente, file di configurazione protetti o secret manager.
  • Usa HTTPS sempre: senza TLS, il token può essere intercettato in transito.
  • Evita i token nella query string: possono finire nei log, nei bookmark o nei referrer.
  • Imposta scadenza e rotazione: un token permanente è più rischioso di uno a durata limitata.
  • Registra i tentativi falliti: utile per auditing e rilevamento di abusi.
  • Applica il principio del privilegio minimo: ogni token dovrebbe autorizzare solo ciò che serve davvero.
  • Valida sempre lato server: non fidarti mai di controlli fatti solo nel frontend.
  • Restituisci messaggi di errore generici: evita di rivelare dettagli inutili sull’implementazione.

Se il progetto cresce, puoi evolvere questo approccio in una soluzione più strutturata con:

  • token per utente salvati in database;
  • scadenza automatica;
  • revoca dei token compromessi;
  • scope o permessi granulari;
  • integrazione con JWT o sessioni server-side, se appropriato.

Un altro consiglio importante: se il token viene usato per accedere a operazioni molto sensibili, valuta anche un secondo fattore di sicurezza, come una conferma esplicita o un controllo aggiuntivo sul ruolo dell’utente.

Riepilogo

Proteggere gli endpoint PHP con un token Bearer è una tecnica semplice ma molto efficace per difendere risorse riservate. Funziona bene per API, pannelli amministrativi, integrazioni tra servizi e richieste automatizzate.

I punti chiave da ricordare sono:

  • leggere il token dall’header Authorization;
  • verificarne il formato e la presenza;
  • confrontarlo con hash_equals();
  • usare codici HTTP corretti come 401 e 403;
  • non salvare segreti nel codice sorgente;
  • usare sempre HTTPS.

Questo approccio non sostituisce un sistema di autenticazione completo, ma è una base concreta e solida per proteggere molte funzionalità in PHP. È particolarmente utile quando vuoi separare bene client e server, mantenendo il controllo degli accessi in modo chiaro e verificabile.

Approfondisci con risorse ufficiali

  • PHP Manuale - hash_equals(): https://www.php.net/manual/it/function.hash-equals.php
  • PHP Manuale - getallheaders(): https://www.php.net/manual/it/function.getallheaders.php
  • PHP Manuale - header(): https://www.php.net/manual/it/function.header.php
  • OWASP API Security Top 10: https://owasp.org/www-project-api-security/
  • OWASP Authentication Cheat Sheet: https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html
  • MDN - HTTP Authorization header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization

SHARE