Aș dori să vă prezint o traducere a articolului Codeproject ce probleme pot apărea atunci când se utilizează mai multe ferestre sau file de browser într-o singură sesiune, permite utilizatorului să restricționeze aplicațiile web și soluții folosind doar o singură fereastră pentru a preveni aceste probleme.
În dezvoltarea aplicațiilor Web, există mai multe probleme de securitate care trebuie reamintite. Una dintre reguli spune:
"Limitați utilizatorii la o fereastră de browser"
HTTP se numește un protocol fără o stare, deoarece fiecare cerere este executată independent, fără a ști ce interogări au fost efectuate înainte de aceasta. Întrucât HTTP nu stochează inițial date de stare, are unele dezavantaje atunci când vine vorba de securitatea și performanța unui site Web. Sesiunea de substituire, multiple solicitări / răspunsuri, concurs de date sunt doar câteva dintre problemele care apar atunci când se utilizează simultan mai multe ferestre sau file de browser.
Există două probleme legate de interzicerea utilizării mai multor ferestre sau file:
- Cum putem distinge între două cereri (GET sau POST) pe partea de server și să aflăm dacă cererea a venit din aceeași fereastră sau dintr-o filă nouă?
2. Cum pot opri un utilizator care încearcă să inițieze o nouă solicitare (GET sau POST) din două ferestre diferite pe partea clientului?
-
Mai jos este un exemplu de acțiuni pe care un utilizator le poate efectua pentru a crea o nouă fereastră sau o filă a browserului:
Notă: Toate ferestrele deschise utilizând comenzile de mai sus împărtășesc aceeași sesiune / cookie-uri în timpul comunicării cu serverul. Când creați o filă nouă / fereastră, browserul folosește o copie exactă a paginii originale.
O soluție pentru determinarea și prevenirea utilizării mai multor file sau ferestre de browser web atunci când lucrați cu o aplicație web
Există două abordări pe care le putem folosi într-o aplicație web:
În detaliu, pas cu pas:
Mai întâi, se solicită pagina Default.aspx.
Următorul script este executat la evenimentul de încărcare a paginii:
În funcția Default.aspx.cs avem funcția GetWindowName () care returnează un nume unic.
Când pagina se încarcă prima dată, numele ferestrei Default.aspx conține o valoare goală (""). Scriptul stabilește numele ferestrei la "implicit" și se deschide din nou în aceeași fereastră. Acum, numele unic al ferestrei este instalat (folosind funcția de pe partea de server GetWindowName ()) și pagina Home.aspx este deschisă.
Scriptul închide Default.aspx imediat după deschiderea Home.aspx.
Notă: De fiecare dată când deschideți o fereastră nouă, window.name este goală (""). Dacă window.name este gol, atunci Internet Explorer 7 și versiuni ulterioare va afișa un mesaj de confirmare:
Dar folosind scriptul de mai jos, putem face ca întrebarea să nu fie întrebată și fereastra va fi închisă automat.
Pe toate celelalte pagini (cu excepția Default.aspx), folosim acest script în secțiunea Head.
Și un astfel de cod în codul corespunzător din spate (Home.aspx.cs):
2. Verificarea antetului HTTP Referer din partea serverului
Acest lucru permite serverului să creeze o listă de backlink pentru nevoi diferite. Și vă permite să urmăriți legăturile "rele".
Dacă interogarea nu are un câmp de referință, aceasta înseamnă că cererea nu a fost generată utilizând următoarele opțiuni:
(Notă:. Când deschideți pagina într-o fereastră nouă sau o filă folosind butonul din mijloc sau dreapta al mouse-ului, valoarea va fi disponibil UrlReferer Dar window.name va fi gol și această condiție vor fi procesate pe partea de client în script-ul pe care le-am adăugat la această pagină).
concluzie
Această soluție vă permite să împiedicați utilizatorul să utilizeze mai multe ferestre de browser. Cu toate acestea, trebuie remarcat că, în același timp, nu există nici o modalitate sigură de 100% pentru a detecta și a împiedica utilizarea mai multor ferestre de browser într-o singură aplicație.
Navigare după înregistrări
Explicați-mi, de ce faceți asta?
Suntem la noi înșine în proiect, dimpotrivă, ne străduim să permitem utilizatorului să deschidă pagini în mai multe file.
Eu, personal, întotdeauna asimilază astfel de restricții.
Principala problemă este că apăs pe Ctrl-N utilizatorul primește o copie exactă a ferestrei deschise curent.
Și în această fereastră, utilizatorul se afla într-o anumită etapă a procesului. Spuneți, trebuie să cheltuiți în mod constant utilizatorul în 3 pași.
Și el se află deja la al doilea pas. Utilizatorul a apăsat CTRL-N și avem o altă copie de Windows de pe al doilea pas și pur și simplu nu se poate distinge între cele două ferestre una de alta și întreaga secvență de pași restrânge atunci când utilizatorul începe să se comuta între ferestre și apăsați pe „Continue“
Tinny ce ... Oamenii niciodată nu fac asta. Cu WindowName, UrlRererrer poate fi ușor schimbat dacă cineva are nevoie de el.
Arătați mai bine arhitectura aplicației dvs., alegerea corectă a platformei etc.
"Limitați utilizatorul la o singură fereastră a browserului" - unde este această regulă direct interesantă?
Înlocuirea sesiunii - nu rezolvi deloc această problemă
multiple solicitări-răspunsuri - la fel cum ați rezolvat această problemă? (dacă înțeleg acest atac DDoS)
Concurența de date este cel mai probabil o arhitectură de aplicații înșelătoare
Dacă într-adevăr doriți să limitați - aceasta este soluția gata 🙂
În general, dacă utilizatorul a deschis o formă de editare a unui obiect și a "înclinat" pagina într-o altă filă de browser. Ați făcut clic pe prima filă "salvați", apoi pe cea de-a doua. Care fila ar trebui să "câștige" atunci când salvează date? Ce se va întâmpla din ceea ce "date intermediare" necesare pentru salvarea paginii și care s-au schimbat deja mai devreme când faceți clic pe "Salvați" pe prima pagină?
Aceasta nu este doar o economie competitivă a datelor, utilizatorul are o copie exactă a primei pagini și nu o putem distinge de original.
În HTML 5, pentru a rezolva această problemă, puteți utiliza depozitul de pe partea clientului, care NU este clonat atunci când creați o copie a paginii.
Și aceasta se face doar pentru a rezolva problema descrisă. Spuneți-mi ce fel de soluție arhitecturală îmi va permite să îndoiesc pagina și să continuu să lucrez pe două pagini absolut identice, fără a distruge contextul și îți voi fi foarte recunoscător!
Să aruncăm o privire la exemple.
1. Despre editarea formularului:
Să presupunem că suntem pe formularul de editare a utilizatorului, completați câmpurile.
Clonăm pagina.
În prima pagină, faceți clic pe Trimiteți.
Dacă totul merge bine cu noi, Actualizați în baza de date.
În a doua pagină, faceți clic pe Trimiteți.
Dacă totul merge bine, avem o altă Actualizare în baza de date.
Total: Se introduc doi utilizatori.
Protejez acest comportament cu absolut logic.
Și aceasta este problema utilizatorului, că el a actualizat același obiect de două ori.
Dacă sarcina este așa cum ați descris, atunci, desigur, nu există probleme și sistemul se poate comporta așa cum ați descris.
Și acum, presupunem că avem o situație puțin diferită (mai întâi voi da un exemplu că dezvoltatorii standardului HTML5):
Utilizatorul este pe site-ul de vânzare bilete pentru avion și a deschis două file (a alunecat una din pagini într-o altă filă). Deoarece utilizatorul poate trece de la o filă la alta, și pentru a trece de la o filă la alta poate fi o situație în care el închide accidental sau în mod deliberat una din file, iar al doilea va fi văzut destul de sigur că el nu a cumpăra un bilet. Acest lucru ar putea duce la faptul că utilizatorul va cumpăra două bilete în loc de una ... Dacă am avea un mecanism care va permite să stabilească faptul că fila a fost „clonat“ am putea oferi utilizatorului un avertisment sau de a efectua orice acțiuni altele care vor împiedica o eventuală eroare în acțiunile utilizatorului .
Sau un alt exemplu: avem un vrăjitor în mai multe etape, starea obiectului care procesează acest vrăjitor este stocat undeva în sesiune cu legare la o anumită pagină. Dacă utilizatorul a refuzat pagina, obținem două pagini care nu pot fi diferențiate, care lucrează simultan cu același obiect și modifică simultan părți din acesta. Când salvezi datele dintr-o pagină, putem obține un obiect incorect în memorie. Pentru a preveni acest lucru, puteți verifica starea reală a obiectului și ceea ce se aștepta la trimiterea cererii din pagină. Dar, din nou, dacă obiectul este foarte complex și există multe domenii, o astfel de verificare poate fi o sarcină dificilă. În acest caz, este posibil să se prevină deschiderea mai multor file pentru astfel de pagini critice.
Ei bine, din nou, ați dat exemple care pot fi implementate pentru filele clonate fără probleme.
Despre rezervarea biletelor: scrieți "când închide accidental sau intenționat una dintre file și văzând al doilea va fi pe deplin sigur că biletul pe care nu la cumpărat".
La noi, de exemplu, plata trece prin "coș" unde utilizatorul adaugă diferite elemente. Iar când plătește pe una dintre file, coșul este șters și datele de achiziție sunt copiate acolo unde este necesar. Deci, dacă va plăti din nou pe o altă filă, va întoarce o eroare că coșul său este gol.
Despre un vrăjitor în mai multe etape: aici, da, cu vrăjitorii totul nu este ușor. Trebuie să luăm în considerare o mulțime de condiții și situații diferite. Aici și înainte / înapoi utilizatorul din browser poate face clic și se deschide noua filă, aceasta este dorința lui.
Dar nimeni nu a spus că este ușor de programat. Cred că dacă faceți un vrăjitor complex, încercați să îl implementați și să-l implementați într-un mod adecvat și să nu limitați utilizatorul.
Am un vrăjitor complex în proiect, dar nu este vorba doar de o mulțime de cod logic, ci de multe.
În general, mi se pare că utilizatorii nu ar trebui să fie limitați.
Ei bine, nu înțeleg, Vadim, dacă ați rezolvat problema mai multor taburi prin programare "tare", apoi onorați și laudați! Doar aici există o mulțime de exemple de situații în care pur și simplu NU trebuie să duplicați filele, deci unde sunt restricțiile impuse utilizatorului? De ce ar trebui să fie păcălit de coșuri de un fel, să se păcălească cu algoritmi? Din moment ce scrieți că programarea nu este un proces ușor, nu are sens să o complici (IMHO) :).
Ceva ce nu am înțeles acest cod. Ești sigur că acest cod funcționează? În general, dacă utilizatorul deschide o filă. Fila va primi ID-ul, va fi scris în sesiunea de pe partea de server. Apoi utilizatorul va închide această filă și va deschide din nou pagina. Deoarece codul de sesiune este deja stocat pe server, obținem InvalidAccess, adică accesul la site este, în general, blocat. Am rezolvat problema prin localStorage (prin jStorage.js pentru a sprijini browsere mai vechi). La deschiderea orice set de pagini întotdeauna variabila globală se schimbă interceptarea convorbirilor telefonice și apoi trimis la solicitarea echo (o configurație de tip variabilă echo = aleatoare ()). Dacă primiți răspunsul de ecou (din altă filă din aceeași funcție ca și interceptarea convorbirilor telefonice setarea bloc variabila = aleatoare ()), aceasta înseamnă a deschide deja o altă filă și vom bloca accesul la site-ul. Numai există o nuanță care unele browsere, cum ar fi IE apela interceptarilor funcția chiar și pentru un set variabilă în aceeași filă, dar alte browsere nu sunt, deci trebuie să compare aleatoriu () este trimis și valoarea primită, în cazul în care se potrivesc, se va solicita aceeași filă , dacă nu, atunci răspunsul a venit dintr-o altă filă. Codul funcționează în mod normal și sub toate browserele live. Dezavantajul este că acest lucru nu este un schimb de cerere-răspuns sincron, iar răspunsul poate veni într-un anumit timp, sau nu vin deloc (în cazul în care doar o singură filă), astfel încât pagina este redat, script-ul începe să lucreze și apoi (de exemplu, 1 secundă), am ecou răspundeți și blocați pagina. Se pare că pâlpâie. Noul Firefox browsere pretutindeni, cu excepția există o întârziere în Firefox și în versiunile noi și vechi sunt procesate instantaneu. În general, implementarea funcționează, dar nu este ideală. Nu există o soluție perfectă aici.