Questa repository è una POC con hardening dimostrativo, non un'affermazione di sicurezza assoluta. Nessun cookie è “inattaccabile”: HTTPS, browser, endpoint, gestione delle chiavi, dipendenze e infrastruttura fanno parte dello stesso confine di sicurezza.
La demo può essere esposta per finalità editoriali in un ambiente isolato, con dati e account fittizi. Non deve accettare pagamenti, dati personali o ordini reali.
| Cookie | Contenuto | Flag | Rischio residuo |
|---|---|---|---|
alifacesAuth |
JWT HS256 con sub, iss, aud, jti, iat, nbf, exp; nessun nome/e-mail |
HttpOnly, Secure su HTTPS, SameSite=Lax, path dell'app |
Un JWT rubato è riutilizzabile fino alla scadenza (1 ora) |
alifacesShopper |
Identificatore guest opaco casuale a 256 bit | stessi flag | È una capability: chi lo ruba vede/modifica il carrello guest |
amaFacesTheme |
nome tema validato su whitelist | HttpOnly, Secure su HTTPS, SameSite=Lax |
Nessun dato affidabile o sensibile |
alifacesLang |
codice lingua validato su whitelist (en, it) |
stessi flag | Nessun dato affidabile o sensibile |
alifacesNotice |
chiave di bundle + argomenti del messaggio da mostrare dopo un redirect, durata 60 s | stessi flag | Chi lo falsifica mostra a sé stesso un messaggio dell'applicazione: la chiave è validata sul bundle, gli argomenti sono limitati e l'output è escapato |
BFCache-Buster |
numero opaco scritto da OmniFaces CacheControlFilter per invalidare la bfcache del browser |
HttpOnly, SameSite=Lax, host-only, cookie di sessione |
Nessun dato applicativo; non è emesso da questo codice |
Tutti i cookie applicativi passano da CookiePolicy, che decide gli attributi in un punto solo:
HttpOnly sempre, nessun Domain (host-only), Path limitato all'applicazione, e Secure quando
la richiesta è HTTPS o quando un reverse proxy dichiara X-Forwarded-Proto: https. Fidarsi
dell'header inoltrato può solo aggiungere il flag, quindi un client che mente danneggia unicamente
sé stesso.
Il flag non viene forzato dallo stage Production. Quella regola sembrava prudente ed era peggio
del problema che voleva risolvere: un deployment in Production servito in chiaro emetteva cookie
che il browser scarta in silenzio, quindi ogni richiesta arrivava con un'identità nuova e il cliente
vedeva il carrello sempre vuoto, senza una riga di log a spiegarlo. Ora in quel caso parte un
WARNING all'avvio — la mancanza del flag su un deployment in chiaro è un allarme, non
un'applicazione rotta. Resta vero che l'esposizione pubblica richiede TLS.
Il cookie ospite viene cancellato al login: a quel punto il carrello da ospite è già stato unito all'account e l'identificatore non serve più. Così la capability non resta nel browser per un anno e la navigazione dopo un eventuale logout riparte con un identificatore nuovo.
Il JWT è firmato, non cifrato. Il server accetta esclusivamente HS256, verifica firma,
issuer, audience, intervallo temporale e subject, quindi risolve l'utente dal direttorio.
Prezzi, stock, ruoli, nome ed e-mail non sono considerati affidabili dal cookie.
- segreto JWT di almeno 256 bit, fornito fuori dal WAR; in
Productionla sua assenza impedisce l'avvio dell'applicazione (una chiave casuale per JVM sloggherebbe tutti a ogni riavvio e farebbe rifiutare da ogni altro nodo i token emessi da questo), mentre in sviluppo resta un fallback casuale con warning in log; - cookie host-only (nessun
Domain), path limitato all'app,HttpOnly,SameSite=LaxeSecurequando la richiesta è HTTPS; - validazione esatta
Origin/ReferersuPOST,PUT,PATCHeDELETE, oltre aSameSite; assenza o mismatch producono403; - bypass CSRF soltanto per Bearer token o protocollo API con header custom, non impostabile da una form cross-site; nessuna policy CORS viene concessa;
- header
nosniff, anti-framing, referrer policy e permissions policy; - identificatore guest con 256 bit di entropia e formato rigorosamente validato;
- nessun
HttpSession: in sviluppo la sua creazione accidentale interrompe la richiesta con lo stack trace del componente colpevole, in produzione viene registrata a livello SEVERE senza restituire un 500 al cliente; - pagina di diagnostica
/status.xhtmlraggiungibile anche inProduction, per scelta: questa è una POC il cui interesse sta proprio nel mostrare su cosa gira (estensioni SIMD scelte da HotSpot, collector, memoria vista da un unikernel). È una decisione con un costo, quindi è esplicita: la pagina nomina host e JVM, e ogni proprietà o variabile d'ambiente il cui nome contenga password, secret, token, credential o key viene sostituita con[redacted]— verificato cheALIFACES_JWT_SECRETnon compaia mai in chiaro. Un deployment che non sia un caso di studio la chiude con il context-paramalifaces.DIAGNOSTICS=false, e allora risponde 404; - la chiave shopper mostrata nella striscia dimostrativa è troncata: il valore intero è quello del
cookie guest, cioè una capability, e stamparlo per esteso vanificherebbe
HttpOnly; - password demo memorizzate come PBKDF2, ma le password in chiaro restano nel sorgente per poterle mostrare: questa directory va sostituita in produzione;
- lo storico ordini dimostrativo non viene seminato in
Production, e fuori daProductionviene saltato per gli account che ne hanno già uno — così unOrderStorecondiviso non se lo ritrova moltiplicato per il numero di nodi.
index.xhtml e product.xhtml sono servite come guscio anonimo con Cache-Control: public, s-maxage=60 e nessun Set-Cookie: non contengono identità, quindi la stessa risposta può
essere riusata per chiunque. Le parti personali arrivano da una chiamata successiva, che è una POST
e quindi non cacheabile.
Due condizioni valgono come requisito di configurazione, non come dettaglio:
- l'edge deve escludere i cookie di identità (
alifacesAuth,alifacesShopper) dalla cache key — non servono al guscio — e includerealifacesLangeamaFacesTheme, che cambiano il markup; - nessun codice deve reintrodurre un
Set-Cookiesu quelle due pagine: sarebbe la via più rapida per far distribuire da una cache condivisa l'identificatore di un visitatore a tutti gli altri. Per questoThemeSwitchereLocaleSwitcherscrivono il cookie solo quando la preferenza arriva esplicitamente dall'URL.
/sitemap.xml e robots.txt sono pubblici per costruzione: elencano solo il catalogo, e
robots.txt tiene i crawler fuori da carrello, login, ordini, API e pagina diagnostica.
/health/ready è pubblico e volutamente muto: risponde UP/DOWN sulla raggiungibilità dello
store e non espone nulla dell'host, che resta materia di /status.xhtml (chiuso in Production).
- Terminare esclusivamente HTTPS, configurare HSTS all'edge e verificare il forwarding sicuro dello schema al container.
- Impostare
ALIFACES_JWT_SECRETin un secret manager eALIFACES_PUBLIC_ORIGINall'origine HTTPS canonica. Ruotare le chiavi; per più servizi preferire firme asimmetriche ekid. - Implementare access token brevi, refresh token con rotazione e revoca/denylist. Il logout attuale cancella il cookie ma non può invalidare un JWT già copiato.
- Sostituire store in-memory e directory demo; garantire TTL, eviction, limiti di cardinalità, persistenza e atomicità del merge guest/account nel backend scelto.
- Mettere rate limiting su login e API, WAF/edge limits, audit trail, metriche e alert.
- Definire una Content Security Policy compatibile con PrimeFaces, eseguire SAST/SCA/DAST, penetration test e scansione delle immagini/container.
- Modellare autorizzazioni per venditori, amministratori, rimborsi e accesso agli ordini; la POC mostra soltanto il flusso cliente.
- Aggiungere pagamenti tokenizzati tramite provider certificato; non gestire carte nella POC.
- Aggiornare PrimeFaces da una RC a una release stabile validata prima del go-live.
Non aprire pubblicamente dettagli di una vulnerabilità sfruttabile contro un'istanza attiva. Usare il canale privato indicato dal maintainer del deployment.