Salta al contenuto principale

Buone pratiche

Usa query parametrizzate per ogni accesso al database

Invia al database separatamente la struttura della query e i valori forniti dall'utente così che l'input non possa mai cambiare il significato dell'SQL. È la difesa definitiva contro la SQL injection e funziona allo stesso modo tra driver e ORM che fanno binding dei parametri.

  • Fai: usa un prepared statement come SELECT * FROM users WHERE email = ? e fai binding del valore.
  • Non fare: costruire SQL per concatenazione come "... WHERE email = '" + email + "'", anche con escaping manuale.

Codifica l'output in base al suo contesto, non solo in ingresso

Applica una codifica consapevole del contesto nel punto in cui i dati vengono resi - corpo HTML, attributo HTML, JavaScript, URL e CSS richiedono ciascuno un escaping diverso. Sanitizzare solo in ingresso è insufficiente perché lo stesso valore può essere sicuro in un contesto e pericoloso in un altro.

  • Fai: affidati al binding automatico del tuo framework (per esempio {{ value }} in Angular o il testo JSX) e codifica per contesto.
  • Non fare: assegnare dati non fidati a sink grezzi come element.innerHTML senza prima sanitizzarli.

Imponi l'autorizzazione sul server per ogni richiesta

Riverifica sul server che il principal autenticato sia abilitato a eseguire l'azione specifica sull'oggetto specifico, a ogni endpoint protetto. I controlli lato client e gli elementi UI nascosti sono solo comodità e non offrono alcuna sicurezza.

  • Fai: verifica la proprietà della risorsa lato server, ad esempio conferma order.userId == currentUser.id prima di restituire /orders/{id}.
  • Non fare: fidarti di un ruolo, un tenant ID o un object ID forniti dal client, o assumere che "loggato" significhi "autorizzato".

Valida e metti in allow-list tutto l'input non fidato sul server

Tratta ogni input (body, query, header, file) come ostile e validalo contro un'allow-list rigorosa di tipi, range e formati attesi prima dell'uso. Mettere in allow-list ciò che è permesso è molto più robusto che tentare di bloccare pattern noti come dannosi.

  • Fai: valida con uno schema e rifiuta tutto ciò che non corrisponde, ad esempio un enum di ["asc","desc"] per un parametro di ordinamento.
  • Non fare: affidarti alla sola validazione lato client, o usare deny-list che gli attaccanti eludono banalmente con codifiche nuove.

Conserva le password con un hash lento, con salt e memory-hard

Usa una funzione di hashing per password costruita allo scopo così che una violazione del database non produca credenziali utilizzabili. Il salt unico per password vanifica le rainbow table e un work factor elevato rende costoso il cracking offline.

  • Fai: fai l'hash con Argon2id (oppure bcrypt/scrypt) con un cost factor calibrato e un salt unico per password.
  • Non fare: conservare in chiaro, usare hash veloci come MD5 o SHA-256 da soli, o riutilizzare un unico salt globale.

Rafforza il cookie di sessione così che non possa fuoriuscire su HTTP semplice, non possa essere letto da JavaScript e non venga allegato sulle richieste cross-site. Questi tre attributi insieme attenuano il furto di sessione via XSS e CSRF.

  • Fai: emetti Set-Cookie: sid=...; Secure; HttpOnly; SameSite=Lax; Path=/ e rigenera l'ID al login.
  • Non fare: esporre l'ID di sessione a JavaScript, inviarlo su HTTP, o mantenere lo stesso ID attraverso un cambio di privilegio.

Imponi HTTPS ovunque e invia HSTS

Servi tutto il traffico su TLS 1.3 con certificati validi e aggiungi l'header Strict-Transport-Security così che i browser rifiutino il downgrade a HTTP. Questo previene intercettazione, manomissione e attacchi di SSL-stripping.

  • Fai: imposta Strict-Transport-Security: max-age=63072000; includeSubDomains; preload e reindirizza HTTP a HTTPS.
  • Non fare: mescolare contenuti HTTP e HTTPS, o affidarti al solo redirect senza HSTS, lasciando la prima richiesta non protetta.

Distribuisci una Content Security Policy rigorosa

Usa uno script-src basato su nonce o hash così che gli script inline iniettati senza il nonce corretto non possano eseguire, rendendo inerti molti payload XSS. La CSP è una potente difesa in profondità sopra l'output encoding.

  • Fai: invia Content-Security-Policy: script-src 'self' 'nonce-'; object-src 'none'; base-uri 'self'.
  • Non fare: indebolirla con 'unsafe-inline' o un * generico, che di fatto disattiva la protezione.

Richiedi MFA resistente al phishing dove conta

Aggiungi un secondo fattore all'autenticazione e preferisci WebAuthn/FIDO2 (passkey, chiavi di sicurezza) per gli account ad alto valore, perché la credenziale è legata all'origine e non può essere sottratta via phishing o rigiocata. Questo blocca la maggior parte dei furti di account anche quando una password trapela.

  • Fai: offri passkey/WebAuthn e ripiega su app authenticator TOTP dove necessario.
  • Non fare: affidarti ai codici usa-e-getta via SMS come unico secondo fattore, dato che sono vulnerabili al SIM-swapping.

Applica il privilegio minimo a ogni account e token

Concedi a ogni utente, servizio, account di database e token API solo i permessi strettamente necessari, e rendi le credenziali a breve durata. Questo contiene il danno quando un singolo componente viene compromesso.

  • Fai: dai all'app un utente DB limitato alle sue tabelle ed emetti token API con scope ristretto e in scadenza.
  • Non fare: connetterti come superuser del database, o distribuire token ampi, a lunga durata e con tutti gli scope "per semplicità".

Applica rate limiting su autenticazione ed endpoint sensibili

Limita il numero di richieste per client e per account in una finestra temporale per attenuare forza bruta, credential stuffing e abuso. Combina il throttling con chiare risposte 429 Too Many Requests e backoff.

  • Fai: applica un limite token-bucket per account e IP a /login, e aggiungi lockout/backoff temporaneo dopo fallimenti ripetuti.
  • Non fare: lasciare illimitati gli endpoint di login, password-reset e token, permettendo tentativi infiniti.

Proteggi le richieste in uscita contro l'SSRF

Valida, metti in allow-list e vincola ogni richiesta lato server il cui URL sia influenzato dall'input dell'utente, e blocca i range di indirizzi interni. Questo impedisce agli attaccanti di raggiungere servizi interni o l'endpoint di metadati cloud.

  • Fai: metti in allow-list host/schemi permessi, blocca i range link-local e privati e disabilita il follow dei redirect.
  • Non fare: scaricare un URL arbitrario fornito dall'utente direttamente, esponendo 169.254.169.254 e i servizi interni.

Mantieni le dipendenze fissate, scansionate e inventariate

Gestisci il codice di terze parti come parte della tua superficie d'attacco: fissa le versioni, scansiona per vulnerabilità note e mantieni un SBOM così da reagire in fretta alle nuove divulgazioni. Per gli script di terze parti caricati nel browser, verificane l'integrità.

  • Fai: committa un lockfile, esegui la scansione delle dipendenze in CI e aggiungi integrity="sha384-..." (SRI) ai tag