2010-07-08 17 views
61

Il problemaBest Practices per il passaggio di dati tra le pagine

Nel stack che abbiamo ri-uso tra i progetti, ci stanno mettendo un po 'troppi dati nella sessione per il passaggio dei dati tra le pagine. Ciò è stato utile in teoria perché impedisce manomissioni, attacchi di riproduzione e così via, ma crea tanti problemi quanti ne risolve.

La perdita di sessione stessa è un problema, sebbene sia principalmente gestito dall'implementazione di Session State Server (o utilizzando SQL Server). Ancora più importante, è difficile rendere il pulsante Indietro funzionante correttamente, ed è anche un lavoro extra per creare una situazione in cui un utente può, ad esempio, aprire la stessa schermata in tre schede per lavorare su diversi record.

E questa è solo la punta dell'iceberg.

Esistono soluzioni alternative per la maggior parte di questi problemi, ma mentre mi allontano, tutta questa frizione mi dà la sensazione che passare i dati tra le pagine utilizzando la sessione sia la direzione sbagliata.

Quello che voglio veramente fare qui è una buona pratica che il mio negozio può usare sempre per il trasferimento di dati tra le pagine e quindi, per le nuove app, sostituire le parti chiave del nostro stack che attualmente si basano su Session .

Sarebbe anche bello se la soluzione finale non si traducesse in montagne di codice idraulico piano.

Soluzioni proposte

sessione

Come accennato in precedenza, appoggiandosi pesantemente sulla sessione sembra come una buona idea, ma rompe il pulsante indietro e causa di alcuni altri problemi.

Ci possono essere dei modi per aggirare tutti i problemi, ma sembra un lavoro extra.

Una cosa che è molto piacevole nell'usare la sessione è il fatto che la manomissione non è un problema. Rispetto a passare tutto tramite QueryString non criptato, si finisce per scrivere molto meno codice di protezione.

Cross-pagina di invio messaggi

A dire il vero ho a malapena considerato questa opzione. Ho un problema con quanto strettamente accoppiato rende le pagine - se inizio a fare PreviousPage.FindControl ("SomeTextBox"), sembra un problema di manutenzione se mai voglio arrivare a questa pagina da un'altra pagina che forse non ha un controllo chiamato SomeTextBox.

Sembra limitato anche in altri modi. Forse voglio arrivare alla pagina tramite un link, per esempio.

querystring

Attualmente sto appoggiato verso questa strategia, come nei tempi antichi. Ma probabilmente voglio che il mio QueryString sia crittografato per renderlo più difficile da manomettere, e mi piacerebbe anche gestire il problema degli attacchi replay.

Su 4 ragazzi di Rolla, there's an article about this.

Tuttavia, dovrebbe essere possibile creare un HttpModule che si occupi di tutto ciò e rimuova tutte le operazioni di creazione di salsicce di crittografia dalla pagina. Abbastanza sicuro, Mads Kristensen has an article where he released one. Tuttavia, i commenti fanno sembrare che abbia problemi con scenari estremamente comuni.

Altre opzioni

Naturalmente questo non è uno sguardo esaustivo alle opzioni, ma piuttosto le principali opzioni che sto prendendo in considerazione. This link contiene un elenco più completo. Quelli che non ho menzionato come Cookie e Cache non sono appropriati allo scopo di passare i dati tra le pagine.

In chiusura ...

Così, come stai gestendo il problema del passaggio di dati tra le pagine? Quali trucchi nascosti hai dovuto aggirare, e ci sono degli strumenti pre-esistenti intorno a questo che li risolvono tutti in modo impeccabile? Do ti senti come se avessi una soluzione di cui sei completamente soddisfatto?

Grazie in anticipo!

Update: Solo nel caso non sto facendo abbastanza chiaro, da 'il passaggio di dati tra le pagine' di cui sto parlando, per esempio, passando una chiave CustomerID da una pagina CustomerSearch.aspx per Customers.aspx, dove il cliente sarà aperto e la modifica può avvenire.

risposta

7

Diversi mesi dopo, ho pensato di aggiornare questa domanda con la tecnica con cui ho finito, dato che ha funzionato molto bene.

Dopo aver giocato con la gestione dello stato della sessione più coinvolta (che ha provocato molti pulsanti interrotti e così via) ho finito con il rollare il mio codice per gestire QueryString crittografato. È stata una grande vittoria: tutti i miei scenari problematici (pulsante Indietro, schede multiple aperte contemporaneamente, stato della sessione persa, ecc.) Sono stati risolti e la complessità è minima poiché l'utilizzo è molto familiare.

Questo non è ancora un mirino magico per tutto, ma penso che sia buono per circa il 90% degli scenari in cui ti imbatti.

dettagli

ho costruito una classe chiamata CorePage che eredita da pagina. Ha metodi chiamati SecureRequest e SecureRedirect.

Così si potrebbe chiamare:

SecureRedirect(String.Format("Orders.aspx?ClientID={0}&OrderID={1}, ClientID, OrderID) 

CorePage analizza il QueryString e crittografa in una variabile QueryString chiamata Coresecure. Quindi la richiesta effettiva è simile al seguente:?

Orders.aspx Coresecure = 1IHXaPzUCYrdmWPkkkuThEes% 2fIs4l6grKaznFGAeDDI% 3d

Se disponibile, attualmente connesso in UserID viene aggiunto alla chiave di crittografia, in modo da riprodurre le attacchi non sono tanto di un problema.

Da lì, è possibile chiamare:

X = SecureRequest("ClientID") 

Conclusione

Tutto funziona senza problemi, utilizzando la sintassi familiare.

Negli ultimi mesi ho anche adattato questo codice per lavorare con casi limite, come i collegamenti ipertestuali che attivano un download - a volte è necessario generare un collegamento ipertestuale sul client che ha un QueryString sicuro. Funziona davvero bene.

Fammi sapere se ti piacerebbe vedere questo codice e lo metterò da qualche parte.

Un ultimo pensiero: è strano accettare la mia risposta su alcuni dei post molto attenti che altre persone mettono qui, ma questa sembra davvero la risposta definitiva al mio problema. Grazie a tutti quelli che mi hanno aiutato a raggiungermi.

+1

Proprio come la crittografia dei commenti di per sé in realtà non risolve l'aspetto della sicurezza del passaggio degli ID in QueryString, rende solo molto più difficile temperare con loro. In un'applicazione protetta si tende ad avere una sorta di identità in sessione, ad esempio il nome utente. Quindi se hai una pagina Orders.aspx? OrderId = 1, nei tuoi livelli inferiori (servizio/azienda) puoi sempre inserire la logica di convalida per assicurarti che l'ordine recuperato da questo ID appartenga effettivamente all'utente che ha effettuato l'accesso all'applicazione. – e36M3

+0

@ e36M3: buon punto. Questo strumento non indica come viene archiviato l'ID utente, è solo un livello sopra Richieste e Reindirizzamento. Quindi potrebbe essere certamente usato in questo modo, sarà sufficiente memorizzare il tuo ID utente in sessione e scrivere il codice di convalida. Sto sicuramente facendo la parte di validazione ora, anche se devo ammettere che sto memorizzando l'UserID in un cookie criptato che non è perfetto. Ma voglio provare a non fare affidamento sulla sessione. E questi non sono progetti di alto profilo. Sempre margine di miglioramento .. –

+2

per favore puoi postare su github? Puoi risolvere il problema di un'altra persona ... – CodeArtist

3

Non lo farei mai. Non ho mai avuto problemi a memorizzare tutti i dati di sessione nel database, caricandolo in base al cookie degli utenti. È una sessione per quanto riguarda qualsiasi cosa, ma mantengo il controllo su di esso. Non rinunciare al controllo dei tuoi dati di sessione sul tuo server web ...

Con un po 'di lavoro, puoi supportare sessioni secondarie e consentire il multi-tasking in diverse schede/finestre.

+0

Quindi, per essere chiari, * state * usando la sessione per passare i dati tra le pagine? Ad esempio, se disponi di un'app cruda con una pagina Clienti, potresti impostare la sessione ("CustomerID") = 5 e quindi eseguire Response.Redirect ("Customers.aspx")? –

+0

No. Sto usando un cookie, per abbinarlo al database, per caricare i dati relativi.Non utilizzo la funzionalità Session fornita da ASP o .NET o PHP, ecc. Io uso una classe (chiamata Session, hah) e il costruttore proverà ad abbinare il cookie degli utenti a una sessione esistente, o ne creerà una nuova . I dati sono quindi collegabili da lì ... – Fosco

+0

Ok, è interessante, posso vedere come potresti costruire un sacco di extra bontà in questo modo. In definitiva, però, usi il tuo oggetto homebrew session per fare i passi fondamentali sopra menzionati, giusto? –

2

Come punto di partenza, trovo l'utilizzo degli elementi di dati critici, come ad esempio un ID cliente, inserito nella stringa di query per l'elaborazione. È possibile rintracciare/filtrare facilmente i dati non validi derivanti da questi elementi e consente inoltre l'integrazione con e-mail o altri siti/applicazioni correlati.

In un'applicazione precedente, l'unico modo per visualizzare un dipendente o un record di richiesta che li coinvolgeva era accedere all'applicazione, effettuare una ricerca per il dipendente o effettuare una ricerca per i record recenti per trovare il record in questione. Ciò divenne problematico e un grande crollo quando qualcuno da un reparto correlato aveva bisogno di fare una semplice visione dei record a fini di controllo.

Durante la riscrittura, ho creato l'ID del dipendente e richiesto Ids disponibili tramite un URL di base di "ViewEmployee.aspx? Id = XXX" e "ViewRequest.aspx? Id = XXX". L'applicazione è stata impostata su A) per filtrare gli ID non validi e B) autenticare e autorizzare l'utente prima di consentirgli di accedere a tali pagine. Ciò che consentiva agli utenti principalmente di fare dell'applicazione era di inviare semplici e-mail ai revisori con un URL nell'e-mail. Quando erano molto di fretta, erano nel loro tempo di elaborazione di massa, erano in grado di semplicemente fare clic su un elenco di URL e fare l'elaborazione appropriata.

Altri dati relativi alle sessioni, come le date di modifica e il mantenimento dello "stato" dell'interazione dell'utente con l'applicazione diventano un po 'più complessi, ma si spera che ciò fornisca un punto di partenza per voi.

41

In primo luogo, i problemi con cui si sta trattando riguardano lo stato di gestione in un ambiente senza stato.Le lotte che stai avendo non sono nuove ed è probabilmente una delle cose che rende lo sviluppo web più difficile rispetto allo sviluppo di Windows o allo sviluppo di un eseguibile.

Per quanto riguarda lo sviluppo Web, per quanto ne so, hai cinque scelte per gestire lo stato specifico dell'utente che può essere utilizzato in combinazione l'uno con l'altro. Scoprirai che nessuna soluzione funziona per tutto. Invece, è necessario determinare quando utilizzare ogni soluzione: stringa

  • Query - stringhe di query sono buone per passare i puntatori ai dati (ad esempio valori di chiave primaria) o valori di stato. Le stringhe di query da sole non dovrebbero essere considerate sicure anche se crittografate a causa della riproduzione. Inoltre, alcuni browser hanno un limite sulla lunghezza dell'URL. Tuttavia, le stringhe di query presentano alcuni vantaggi, ad esempio che possono essere aggiunte ai segnalibri e inviate via e-mail alle persone e sono intrinsecamente prive di stato se non vengono utilizzate con altri elementi.

  • Cookie: i cookie sono utili per archiviare quantità minime di informazioni per un determinato utente. Il problema è che i cookie hanno anche una limitazione di dimensione, dopo di che semplicemente troncerà i dati, quindi devi stare attento a mettere i dati personalizzati in un cookie. Inoltre, gli utenti possono uccidere i cookie o interromperne l'uso (anche se ciò impedirebbe l'uso della Sessione standard). Simile alla query stringhe, i cookie sono migliori, IMO, per i puntatori ai dati rispetto ai dati stessi, a meno che i dati non siano minuscoli.

  • Dati modulo: i dati del modulo possono richiedere un po 'di informazioni, tuttavia al costo dei tempi postali e in alcuni casi dei tempi di ricarica. ViewState di ASP.NET utilizza variabili di modulo nascoste per conservare le informazioni. Passare i dati tra le pagine utilizzando qualcosa come ViewState ha il vantaggio di funzionare meglio con il pulsante Indietro, ma può facilmente creare pagine ginormous che rallentano l'esperienza per l'utente. In generale, il modello ASP.NET non funziona sulla pubblicazione su più pagine (anche se è possibile), ma lavora sui post sulla stessa pagina e da lì sulla pagina successiva.

  • Sessione: la sessione è utile per le informazioni relative a un processo con cui l'utente sta procedendo o per impostazioni generali. È possibile memorizzare un bel po 'di informazioni in sessione al costo della memoria del server o dei tempi di caricamento dai database. Concettualmente, Session funziona caricando tutto il batuffolo di dati per l'utente in una volta sola dalla memoria o da un server di stato. Ciò significa che se hai una serie di dati molto ampia probabilmente non vuoi metterla in sessione. Session può creare alcuni problemi con i pulsanti posteriori che devono essere valutati rispetto a ciò che l'utente sta effettivamente cercando di realizzare. In generale, troverai che il pulsante Indietro può essere la rovina dello sviluppatore web.

  • Database: l'ultima soluzione (che può essere nuovamente utilizzata in combinazione con altri) è quella di memorizzare le informazioni nel database nello schema appropriato con una colonna che indica lo stato dell'elemento. Ad esempio, se si stava gestendo la creazione di un ordine, è possibile memorizzare l'ordine nella tabella Ordine con una colonna "stato" che determina se si trattava di un ordine reale o meno. Si memorizzerebbe l'identificativo dell'ordine nella stringa di query o nella sessione. Il sito Web continua a scrivere i dati nella tabella per aggiornare le varie parti e gli elementi figlio fino a quando l'utente è in grado di dichiarare che sono stati eseguiti e lo stato dell'ordine è contrassegnato come un ordine reale. Ciò può complicare i report e le query in quanto tutti devono differenziare gli elementi "reali" da quelli in corso.

Uno degli elementi menzionati nel collegamento successivo era Application Cache. Non lo considererei specifico per l'utente poiché è esteso all'applicazione. (Ovviamente può essere un incarnato di scarpe specifico per l'utente, ma non lo consiglierei neanche a). Non ho mai giocato con la memorizzazione dei dati nel HttpContext al di fuori di passarlo a un gestore o un modulo, ma sarei scettico sul fatto che fosse diverso dalle soluzioni sopra menzionate.

In generale, non esiste una soluzione per domarli tutti. L'approccio migliore è quello di assumere su ogni pagina che l'utente avrebbe potuto navigare verso quella pagina da qualsiasi luogo (al contrario di presumere che ci sono arrivati ​​usando un link su un'altra pagina). Se lo fai, i problemi con i pulsanti posteriori diventano più facili da gestire (anche se è ancora doloroso). Nel mio sviluppo, utilizzo ampiamente i primi quattro e, occasionalmente, ricorro all'ultima soluzione quando ne ha bisogno.

+0

Ciao Thomas, grazie per la risposta. Ho accettato la risposta di sw12345 perché non ero tanto alla ricerca dei pro e dei contro delle varie opzioni quanto di una visione avanzata degli strumenti che possono aiutare a risolvere questo problema, in particolare strumenti che potrebbero aiutarmi ad automatizzare la crittografia di querystring in modo trasparente. –

9

OK, quindi voglio prefigurare la mia risposta con questo; Thomas ha chiaramente la risposta più precisa e completa finora per le persone che iniziano ad essere fresche. Questa risposta non è per niente vinta. La mia risposta proviene dal punto di vista di "uno sviluppatore di affari". Come tutti sappiamo troppo bene; a volte non è fattibile spendere soldi per riscrivere qualcosa che già esiste e "funziona" ... almeno non tutto in una volta. A volte è meglio implementare una soluzione che ti consenta di migrare verso un'alternativa migliore nel tempo.

L'unica cosa che direi che Thomas manca è; stato javascript sul lato client. Dove lavoro, abbiamo riscontrato che i clienti si aspettano sempre più applicazioni di tipo "Web 2.0". Abbiamo anche riscontrato che questo tipo di applicazioni di solito comporta una maggiore soddisfazione degli utenti. Con un po 'di pratica e l'aiuto di alcune librerie javascript davvero fantastiche come jQuery (abbiamo persino iniziato a usare GWT e l'abbiamo trovato IMPRESSIONANTE) comunicare con i servizi REST basati su JSON implementati in WCF può essere banale. Questo approccio fornisce anche un ottimo modo per iniziare a muoversi verso un'architettura basata su SOA e pulire la separazione dell'interfaccia utente e della logica aziendale.

Ma sto divagando.

Mi sembra che tu abbia già un'applicazione e hai già esteso i limiti della gestione dello stato della sessione integrata in ASP.NET. Quindi ... ecco il mio suggerimento (supponendo che tu abbia già provato la gestione delle sessioni fuori processo di ASP.NET, che è notevolmente migliore rispetto alla gestione delle sessioni in-process/on-box, e sembra che tu lo abbia perché hai menzionato esso); NCache.

NCache fornisce una sostituzione "drop-in" per le opzioni di gestione delle sessioni di ASP.NET. È semplicissimo da implementare e potrebbe "bandire" la tua applicazione più che abbastanza per farti passare attraverso - senza alcun investimento significativo nel refactoring della base di codici esistente immediatamente.

È possibile utilizzare il tempo e il denaro in più per iniziare a ridurre il debito tecnico concentrando il nuovo sviluppo su cose con valore aziendale immediato - utilizzando un nuovo approccio (come ad esempio una qualsiasi delle alternative offerte nelle altre risposte o miniera) .

solo il mio pensiero.

+0

sw12345: Sw, grazie per la risposta riflessiva. L'ho accettato perché è più il tipo di risposta che sto cercando - la panoramica di Thomas sulle varie strategie è completa, ma sapevo già che roba ed evento ne menzionavano molto nella mia domanda vera e propria. Volevo strategie più avanzate da esaminare. Grazie! –

3

Dopo aver attraversato tutti gli scenari di cui sopra e risposte e questo link Data pasing methods Il mio consiglio finale sarebbe:

COOKIES per:

  • ENCRYPT
  • ENCRYPT [di userId] [ProductID]
  • ENCRYPT [..] xyzIds
  • ENCRYPT [ecc ..]

DATABASE per:

  • set di dati per ID BISCOTTO
  • DataTable ID cookie
  • tutti gli altri pezzi di grandi dimensioni per ID BISCOTTO

Il mio consiglio dipende anche dal di sotto statistiche e questo collegamento dettagli Data pasing methods:

enter image description here

Problemi correlati