Regola
Evita la memorizzazione nella cache di
variabili globali non intenzionali. Nei server Node.js
e Python, le variabili globali persistono tra
le richieste, causando data leak e race condition. Linguaggi supportati: JavaScript, TypeScript, PythonIntroduzione
Le variabili globali nei server Node.js persistono per l'intera durata del processo, non solo per una singola richiesta. Quando i gestori di richieste memorizzano i dati degli utenti in variabili globali, tali dati rimangono accessibili alle richieste successive provenienti da utenti differenti. Questo crea vulnerabilità di sicurezza in cui i dati di sessione, i token di autenticazione o le informazioni personali dell'utente A vengono divulgati all'utente B.
Perché è importante
Implicazioni di sicurezza (data leak): Le variabili globali che memorizzano nella cache dati specifici dell'utente creano leak di dati tra richieste diverse. Lo stato di autenticazione, i dati di sessione o le informazioni personali di un utente diventano visibili ad altri utenti, violando la privacy e i confini di sicurezza.
Race condition: Quando più richieste concorrenti modificano la stessa variabile globale, c'è un'alta probabilità di comportamenti imprevisti. I dati dell'utente A potrebbero essere sovrascritti dalla richiesta dell'utente B a metà dell'elaborazione, portando a calcoli errati, stati corrotti o utenti che visualizzano i dati altrui.
Complessità di debug: I problemi causati dalla memorizzazione nella cache tramite variabili globali sono notoriamente difficili da riprodurre perché dipendono dai tempi delle richieste e dalla concorrenza. I bug si presentano in modo intermittente in produzione sotto carico, ma raramente emergono durante i test di sviluppo a singolo thread.
Memory leak: Le variabili globali che accumulano dati senza alcuna pulizia crescono indefinitamente nel tempo. Ogni richiesta aggiunge ulteriori dati a cache o array globali, esaurendo infine la memoria del server e rendendo necessari riavvii del processo.
Esempi di codice
❌ Non conforme:
let currentUser = null;
let requestData = {};
app.get('/profile', async (req, res) => {
currentUser = await getUserById(req.userId);
requestData = req.body;
const profile = await buildUserProfile(currentUser);
res.json(profile);
});
function buildUserProfile(user) {
return {
name: currentUser.name,
data: requestData
};
}
Perché è errato: Le variabili globali currentUser e requestData persistono tra le richieste. Quando più richieste vengono eseguite in modo concorrente, la richiesta dell'utente B può sovrascrivere currentUser mentre buildUserProfile() dell'utente A è ancora in esecuzione, facendo sì che l'utente A visualizzi i dati dell'utente B.
✅ Conforme:
app.get('/profile', async (req, res) => {
const currentUser = await getUserById(req.userId);
const requestData = req.body;
const profile = buildUserProfile(currentUser, requestData);
res.json(profile);
});
function buildUserProfile(user, data) {
return {
name: user.name,
data: data
};
}
Perché questo è importante: Tutti i dati specifici della richiesta sono memorizzati in variabili locali con uno scope limitato al gestore della richiesta. Ciascuna richiesta dispone di uno stato isolato che non può propagarsi ad altre richieste concorrenti. Le funzioni ricevono i dati tramite parametri anziché accedere allo stato globale, eliminando le race condition.
Conclusione
Mantieni tutti i dati specifici della richiesta in variabili locali o negli oggetti di richiesta forniti dal tuo framework. Utilizza le variabili globali solo per stati realmente condivisi come configurazioni, pool di connessioni o cache di sola lettura. Quando lo stato globale è necessario, applica controlli di concorrenza adeguati e assicurati che i dati non siano mai specifici di un singolo utente.

