Le migliori pratiche per i controlli di sicurezza, in superficie o strato profondo? [chiuso]

3

Prendiamo un'app WebServices sul lato server, dobbiamo assicurarci che tutte le funzioni applichino tutte le regole di sicurezza e mantenga il codice pulito.

In tal caso, di solito preferisco posizionare i miei controlli di sicurezza sui livelli superiori. Non appena l'utente chiama una funzione, controllo se ha i diritti per accedervi o meno. Ma questa strategia non sempre funziona, se abbiamo bisogno di recuperare informazioni dal database prima di eseguire tutti i controlli, per esempio.

Questa è una cattiva idea? Dovrebbe essere meglio inserire i controlli di sicurezza negli strati profondi, appena prima / dopo l'accesso al database? Sto cercando di capire l'approccio migliore per un sistema che ha molti controlli di sicurezza ed evita di creare grandi spaguetti.

La domanda potrebbe essere come "Quali sono le migliori pratiche per assicurarti che un'applicazione sia sicura e che il codice sia facile da mantenere?"

    
posta NLemay 12.03.2014 - 20:54
fonte

2 risposte

0

Trattare la sicurezza come una preoccupazione separata e gestirla in un livello sopra la logica dell'applicazione è una buona pratica.

Un progetto a cui ho partecipato è stato un ottimo esempio. Ha coinvolto una famiglia di servizi web. L'evoluzione del nostro controllo dell'autorizzazione è andata così (è un po 'Java-centric, ma si spera che l'idea sia chiara):

  • In primo luogo come un vaso condiviso in bundle in tutti i servizi.

Tuttavia, come abbiamo ottimizzato la logica di sicurezza, ci ha costretti a ricostruire e ridistribuire tutto. Yuck.

  • Avanti un jar condiviso che ha implementato un filtro JEE, in bundle con tutti i servizi.

Questo era meglio, ma qualsiasi modifica ci ha ancora richiesto di ricostruire & ridistribuire tutto.

  • Successivamente come filtro Tomcat che abbiamo implementato con Tomcat, al di fuori del file .war

Meglio ancora. Ma i nostri ritocchi richiedevano ancora una distribuzione e amp; riavvio dei server Tomcat.

  • Finalmente un proxy inverso che si comportava come un proprio servizio separato dagli altri servizi, che prendevano tutte le richieste e inoltrava le richieste valide inoltrate al server giusto, oppure restituiva un errore "non autorizzato".

E questo ha funzionato come un incantesimo, perché la modifica dei problemi di autorizzazione richiedeva solo una ricostruzione e la ridistribuzione di un servizio: il proxy inverso.

Quindi, vedi, in quel caso abbiamo finito per estorcere del tutto la sicurezza verso l'alto e fuori dal servizio.

Sono d'accordo con la tua sensazione che spingere la sicurezza più in alto nello stack di chiamate come un gate rende la logica di implementazione molto più pulita e più facile da gestire. Se si combinano la logica dell'applicazione con i controlli di sicurezza, c'è il rischio di fare un lavoro extra prima di scoprire (whoops) che non sono autorizzati a fare il passaggio 3. O peggio, potrebbe essere una situazione di rollback in cui l'app deve effettivamente disfare cosa ha fatto nel passaggio 2.

È utile considerare la sicurezza come un livello separato, indipendentemente dal fatto che quel livello sia in codice, un filtro servlet o un proxy upstream. Anche se la sicurezza è una lista di acquisti di azioni, determinare cosa vogliono fare in anticipo e quindi convalidare che sono autorizzati a fare tutto ciò prima che inizi il lavoro effettivo. Ciò fornisce una separazione davvero importante delle preoccupazioni.

...

Un'altra pratica che ho trovato che semplifica notevolmente i problemi di sicurezza sta legando le regole di sicurezza a "ruoli" o "ambiti". Dite freddo, il cliente X vuole fare operazioni X, Y and Z , e questo richiede scope M and P . Una rapida ricerca (possibilmente in cache) risponde rapidamente se le operazioni che vogliono fare sono coperte dagli ambiti che hanno.

Quanto ampia o granulare gli ambiti è solo una domanda di progettazione, ma consente di essere ampia o granulare, se necessario.

    
risposta data 12.03.2014 - 21:33
fonte
8

Ci sono due aspetti di questo problema ed entrambi dovrebbero essere soddisfatti per far funzionare una buona applicazione:

  1. Fail Fast - con l'utente che riempie tutti i dati, premi il pulsante di azione, attendi 5 secondi, solo per fallire poiché un testo all'inizio del modulo dovrebbe avere almeno 3 caratteri o un trattino è stato dimenticato è una pessima esperienza - fai i tuoi controlli di sicurezza e convalida il più vicino possibile all'inizio della transazione, e fallisci non appena scopri un problema. Ciò significa che le convalide dell'interfaccia utente sono molto importanti per un'esperienza fluida e persino i controlli sul lato server prima che il "sollevamento pesante" sia importante.
  2. Non fidarti di nessuno - i client sono facilmente compromessi, le API dei servizi sono esposte allo spoofing, potrebbero mancare implementazioni di terze parti - non fidarti che una precedente convalida è stata fatta e assicurati il più basso possibile i dati rimangono coerenti e la transazione è autorizzata. Questo è il motivo per cui imponi vincoli alle tue tabelle di dati e non solo fai affidamento sulla logica di business per mantenere coerenti i tuoi dati.

Bottom line - ogni layer dovrebbe fare le proprie validazioni sul suo input e sul suo output, anche se ciò significa che alcune convalide vengono fatte più di una volta in una transazione. Potrebbe sembrare che sia "meno facile da gestire" poiché è possibile implementare una convalida più di una volta, ma ogni convalida ha il proprio merito e la propria importanza: la convalida del livello superiore per un'esperienza utente migliore e le convalide di livello inferiore per la sicurezza. / p>     

risposta data 12.03.2014 - 21:17
fonte

Leggi altre domande sui tag