Processo di autenticazione asincrono vs. sincrono

1

Attualmente sto sviluppando un'applicazione web usando Node.js (lato server JavaScript) e MongoDB (database NoSQL).

Sono nella fase in cui devo progettare l'autenticazione e ho avuto una domanda sulla programmazione asincrona.

Uno dei vantaggi dell'utilizzo di Node.js è che tutto può essere programmato per essere asincrono e quindi non bloccante quando si eseguono operazioni di I / O.

  • Nel caso dell'autenticazione, dovrei scrivere tutto in modo sincrono?

Ho paura che un utente malintenzionato possa inviare spam al mio server con richieste che porterebbero alla creazione di account duplicati (o altri oggetti) e forse problemi di sicurezza in seguito.

MongoDB non supporta transazioni come SQL.

  • Ho ragione di preoccuparmi dei processi di autenticazione asincrona?
posta Ko Ichi 19.06.2013 - 10:34
fonte

2 risposte

1

Gestire le richieste in modo sincrono su un server basato su eventi ti lascia aperta a DOS semplice, e sicuramente ha un impatto molto negativo sulle prestazioni. Indipendentemente dal tipo di server che si utilizza, un sistema di autenticazione robusto dovrebbe fornire una protezione contro la scansione della forza bruta.

La pratica più comune che ho visto per la protezione dalla scansione brute force è quella di disabilitare un account dopo un certo numero di accessi non riusciti - che, IMHO, è un DOS stesso. Un approccio più pratico è quello implementato da fail2ban - dopo un certo numero di tentativi falliti da un particolare indirizzo remoto, quell'indirizzo ottiene un ban temporaneo al firewall.

La soluzione che ho usato in passato consiste nell'implementare code brevi per mutex sul nome utente e sull'indirizzo IP di origine: l'autenticazione non viene verificata finché una richiesta non ha entrambi i mutex. Se una coda è piena, la richiesta viene immediatamente respinta. Ciò fornisce ancora un po 'di scope per DOS, ma il suo ambito dovrebbe essere molto meglio contenuto.

Tutti questi possono essere gestiti in modo asincrono.

    
risposta data 19.06.2013 - 11:52
fonte
1

Quando si ha a che fare con il sincronismo, un buon modo di pensare riguarda lo stato . Stato è tutto ciò che deve essere conservato in alcuni archivi di dati (che possono essere RAM, dischi, ... qualunque cosa, e non necessariamente sul server) in modo che l'elaborazione possa in definitiva procedere e avere successo.

Quando si fanno chiamate sincrone (genericamente, non specificamente con Node.js), il chiamante è un thread di esecuzione su qualche macchina, e lo "stato" è ciò che "thread" dell'esecuzione sa: posizione corrente nel codice, le sue variabili locali, il suo stack di chiamate. Il chiamante mantiene quello stato nella RAM per la durata della chiamata; questa è la definizione di una chiamata sincrona: mentre la chiamata non è terminata, il chiamante è bloccato. I dettagli possono variare a seconda del linguaggio di programmazione e di come viene interpretato / compilato, ma per la maggior parte delle lingue, ogni thread di esecuzione (un concetto di linguaggio) viene mappato su un thread di sistema (un concetto di sistema operativo), che significa che lo stato include una voce nella tabella di sistema dei thread, un po 'di spazio nelle strutture dello scheduler e lo stack di thread .

Ogni thread di sistema ha il proprio stack, assegnato quando il thread è stato creato. Le dimensioni predefinite per questo stack dipendono dal sistema operativo e potrebbero essere regolate a livello di programmazione. Su Linux, una pila di thread ha dimensioni 1 MB per impostazione predefinita. Questo è 1 MB di spazio indirizzo , non di RAM: le pagine effettive vengono allocate quando vi si accede, quindi un thread tipico utilizzerà solo alcune dozzine di kilobyte di "vera RAM". Anche se i dettagli variano molto a seconda del contesto, la linea di fondo è la seguente: in un'applicazione tipica, normalmente puoi gestire qualche centinaio di thread alla volta - il che significa che il tuo server può ospitare alcune centinaia in corso chiamate sincrone contemporaneamente . Oltre a questo, devi pensare.

Chiamate asincrone rimuovono questa gestione dello stato basata su thread: il chiamante riprende immediatamente il controllo e può quindi fare qualcos'altro o addirittura uscire. Tuttavia, devi comunque mantenere qualche stato da qualche parte, se non altro per ricordare che c'è una chiamata in corso e sapere cosa si dovrebbe fare con il risultato. Il punto di partenza asincrona consiste nel fare una gestione manuale e dettagliata di questo stato, che può essere piccolo come un ID di sessione di 16 byte o uno stato core simile, consentendo così molte più chiamate simultanee. A seconda del contesto, potresti persino essere in grado di scaricare lo stato sul client (il che implica, ovviamente, problemi di sicurezza aggiuntivi da affrontare). Tuttavia, l'implementazione diventa molto più complessa quando si procede in modo asincrono, e la complessità di solito viene fornita con lavoro extra, bug extra e quindi vulnerabilità extra.

Quindi andare asincrono è un ottimizzazione , e quindi dovrebbe essere previsto solo se la situazione rende la complessità e lo sforzo extra. Come per tutti gli aspetti relativi alle prestazioni, tali ottimizzazioni dovrebbero essere posticipate fino a quando un serio problema correlato alla prestazione è stato debitamente rilevato, monitorato e misurato. "L'ottimizzazione prematura è la radice di tutti i mali."

Quindi ti suggerisco di scrivere per primo tutto il tuo codice in modo sincrono. Quindi, e solo allora, i test di prestazione realistici diranno se le chiamate sincrone saranno sufficienti o meno; e se andare in asincrono è davvero giustificato, a quel punto saprai molto di più sulla tua applicazione, rendendoti pronto (o almeno più pronto) ad affrontare la complessità intrinseca della programmazione asincrona.

    
risposta data 19.07.2013 - 15:19
fonte

Leggi altre domande sui tag