[ASP.NET MVC] Podmiana id w query stringu

0

Witam. Dopiero zaczynam z asp.net mvc i zastanawia mnie jedna rzecz.
Czesto przekazujemy jako parametr jakiegos produktu w id sesji, czy po prostu renderujemy na stronie grupe action linkow, gdzie kazdy bedzie mial w query stringu parametr id produktu.

W jaki sposob zabezpieczyc sie teraz przed nieautoryzowana zmiana id? Skoro wszystko jest jawne, to czy nalezy to recznie szyfrowac? Bo chyba raczej nie trzymac stan w sesji uzytkownika? A moze ponownie sprawdzac czy uzytkownik czy wybrany id, jest z wczesniejszego resulta? Tylko co jesli pobranie takich wiaze sie z duzym czasem przetwarzania?

Chodzi mi o to, jak w najprostrzy sposob automatycznie zabezpieczyc sie przez takimi rzeczami jak prosta podmiana id'ka w linku :)

0

Bardzo chciałem zrozumieć o co chodzi, ale nie potrafię. W jaki sposób chcesz przekazać "parametr produktu w id sesji"? O co w ogóle w tym zdaniu chodzi? Dlaczego nie chcesz trzymać stanu w sesji użytkownika? Przecież po to ona jest.

1

sprawdzaj po stronie serwera, czy dany użytkownik może wykonać akcję na danym obiekcie. nigdy nie polegaj na danych, które przychodzą od klienta.

0

@Rev: Trzymanie tego w sesji nie ma sensu, gdyz moga to byc duze ilosci danych, ktore przez 20 minut beda zajmowaly pamiec, a uzytkownik moze zamknac strone w dowolnym momencie.
@ŁF: a jesli sprawdzam to ponownie po stronie serwera i nie trzymam tego w sesji i zajmuje to sporo czasu? Wtedy dzialanie strony jest conajmniej słabe.

W zwyklym ASP.NET'cie np w takim gridzie wykonujac akcje na jakims wierszu, mozna sie pozniej poslugiwac propertisem DataKeys i wydobywac sobie np id czegos co mamy przypisanego do wiersza i bylo to calkiem bezpieczne. Jak zatem podobny stopień bezpieczeństwa uzyskać w MVC, nie zmniejszając wydajności strony czy bezpieczeństwa.

Jedyne co mi przychodzi do głowy to takie witalne rzeczy jak id zaszyfrować (pytanie czy jest jakiś prosty sposób, np atrybut secure, który dane pole z modelu, przy renderowaniu w widoku automatycznie by szyfrował). w SPACJA końcu nie będe trzymał w sesji setek tysięcy rekordów, tylko po to by sprawdzić czy ten przekazany jest poprawny, jak i nie będe kolejnego długiego selecta do tego zapuszczał.

0

I co, każdemu odwiedzającemu pobierasz setki tysięcy rekordów? Mam wrażenie, że chcesz coś za bardzo przekombinować i znów nie potrafię sobie wyobrazić sytuacji o której mówisz. Spróbuj nakreślić jakiś przykład.

1
wasiu napisał(a)

Jak zatem podobny stopień bezpieczeństwa uzyskać w MVC, nie zmniejszając wydajności strony czy bezpieczeństwa.

Jedyne co mi przychodzi do głowy to takie witalne rzeczy jak id zaszyfrować (pytanie czy jest jakiś prosty sposób, np atrybut secure, który dane pole z modelu, przy renderowaniu w widoku automatycznie by szyfrował). w SPACJA końcu nie będe trzymał w sesji setek tysięcy rekordów, tylko po to by sprawdzić czy ten przekazany jest poprawny, jak i nie będe kolejnego długiego selecta do tego zapuszczał.

  1. Aplikacje w MVC są z natury bardziej wydajne niż WebForms.
  2. Przekazywanie parametrów(o ile to nie hasła) przez GET/QueryString nie jest niebezpieczne. Niebezpieczne jest to, jak programista z nich korzysta.
  3. Nie wierz w to, co przychodzi z przeglądarki.
  4. Security through obscurity = no security.
  5. Jeżeli w jednej tabeli znajdują się dane do których uprawnienia są per wiersz, to autoryzację i tak powinieneś napisać.
  6. Jeśli select w oparciu o id długo się wykonuje, to masz skopaną strukturę(albo boisz się, że będzie wolno, bo nie wiesz jak wydajne są silniki bazodanowe)
select count(*) 
from products 
inner join users 
     on products.ownerId = users.Id 
where products.id=12 
and users.userName='wasiu'
 
select count(*) 
from products 
inner join userRoles 
     on products.ownerRoleId=userRoles.roleId 
inner join users 
     on userRoles.userId = users.Id 
where products.id=12 
and users.userName='wasiu' 

jeśli >0 to user ma uprawnienia.
Jak chcesz żeby było trochę szybciej to zaszyj to w stored procedure.

0

Panowie, w chwili obecnej sprowadzam to do prostego przykładu, a w praktyce i tak przekłada się to na stored procedury, które mają po kilkadziesiąt/set lini kodu, a nie tam proste selecty z paru tabel. A co do skopanej struktury to często faktycznie bywa, że jest skopona bo ktoś kilkanaście lat temu tak sobie wymyślił i a klient ani myśli o migracji do nowej bazy, czy zmienianiu architektury.

Więc sprowadzając to do prostego przykładu. Mam procedure co zwraca jakiś zakres danych (po filtrowaniach itp) i trwa to powiedzmy 10s, czyli zajebiście długo. Przekazuje wynik do tabeli, a użytkownik w każdym wierszu ma actionlink'a z id wyniku, który po kliknieciu przekazywany jest strony pokazującej dany wynik w szczegółach (np jakiś skomplikowany raport - kolejne 15s).

I w całym poście chodzi o to czy:
a) trzymamy w sesji wyniki kluczy do których użytkownik ma dostęp i przy przejściu do raportu sprawdzamy czy się zgadza.
b) wykonujemy ponownego selecta i tracimy 10s by to sprawdzić (to w ogóle bez sensu ale z tego co zauważyłem często tak jest w entity framework)
c) encryptujemy id'ka i w takiej formie przekazujemy go do widoku wyników, a odkodowujemy w kontrolerze raportu

Lub też coś innego, co by było wspierane automatycznie przez mvc. Czyli jak najprościej i najwydajniej to zrobić. Ot tyle :)
Przepraszam jeśli mój pierwszy post był troche niejasny, dziś zdecydowanie nie jest mój dzień ;)

0

Ad a) jeśli rozmiar sesji razy ilość użytkowników ma sensowny rozmiar, to jest to najlepsza, bo najprostsza i skuteczna opcja.
Ad b) użyj cache do zapytań, w zależności od ilości danych na statycznym obiekcie (mało) lub na memcached, velocity itp (dużo).
Ad c) asp-koszmar-programisty-net ma swój zajebisty viewstate, który dzięki dorzuceniu od kilku do - bagatela - kilkuset kB do rozmiaru strony (i do rozmiaru przesyłanych postem i ajaksem danych) chroni integralność danych z nią powiązanych. coś jakby sesja, ale odbijana pomiędzy przeglądarką a serwerem. brzydkie rozwiązanie, ale gotowe, skuteczne i wspierane przez giganta. w takiej sytuacji nic nie potrzebujesz szyfrować, trzymasz sobie wszystkie potrzebne dane w prywatnych zmiennych "instancji" obiektu obsługującego żądania klienta. zresztą co ja tłumaczę, każdy normalny webdeveloper .net zna to rozwiązanie (i brzydzi się go).

1
ŁF napisał(a)

Ad c) asp-koszmar-programisty-net ma swój zajebisty viewstate, który dzięki dorzuceniu od kilku do - bagatela - kilkuset kB do rozmiaru strony (i do rozmiaru przesyłanych postem i ajaksem danych) chroni integralność danych z nią powiązanych. coś jakby sesja, ale odbijana pomiędzy przeglądarką a serwerem. brzydkie rozwiązanie, ale gotowe, skuteczne i wspierane przez giganta. w takiej sytuacji nic nie potrzebujesz szyfrować, trzymasz sobie wszystkie potrzebne dane w prywatnych zmiennych "instancji" obiektu obsługującego żądania klienta. zresztą co ja tłumaczę, każdy normalny webdeveloper .net zna to rozwiązanie (i brzydzi się go).

W MVC się tego nie używa ;] Skoro używamy MVC to zazwyczaj bez *.aspx'ów i ViewState'a/PostBack'a.

0

ad a) Sesja wydaje się ok, pod warunkiem, że ktoś sobie do ulubionych nie wrzuci /Home/12. Wtedy wizyta wygląda tak: przekierowanie na stronę logowania, powrót na stronę /Home/12. W żadnym momencie nie wchodzisz na stronę zawierającą zbiór id do których ma uprawnienia, ergo w sesji nie ma danych względem których można dokonać autoryzacji.
ad b) Nie musisz zwracać całego zbioru wyników, żeby sprawdzić czy zawiera on konkretne id. EF nie jest lekarstwem na całe zło i czasem zwyczajnie trzeba zrobić ExecuteReader/ExecuteScalar. Choćby ze względu na wydajność w przypadku dużych ilości danych(np. raportów). Trzeba dopisać nowe procedury, być może dodać tabele/indeksy/kolumny.
ad c) Nie ma znaczenia, czy link prowadzi do /Home/12, /Home/Zbig12niew, czy /Home/23bjk24h3g4o23ueh23. Jeśli ktoś zdobędzie link to i tak dostanie zbiór danych.

a + c
Jeśli szyfrowanie będzie oparte o zmienną per user w sesji, to nie będzie można przesyłać linków innym, linki będą wygasać(brak ulubionych) i za każdym razem, gdy będziesz musiał wyświetlać dużą liczbę id, konieczne będzie zaszyfrowanie całego zbioru kluczowych/wrażliwych danych(a to też trwa).

0
j_s_r_n napisał(a)

ad a) Sesja wydaje się ok, pod warunkiem, że ktoś sobie do ulubionych nie wrzuci /Home/12. Wtedy wizyta wygląda tak: przekierowanie na stronę logowania, powrót na stronę /Home/12. W żadnym momencie nie wchodzisz na stronę zawierającą zbiór id do których ma uprawnienia, ergo w sesji nie ma danych względem których można dokonać autoryzacji.
ad b) Nie musisz zwracać całego zbioru wyników, żeby sprawdzić czy zawiera on konkretne id. EF nie jest lekarstwem na całe zło i czasem zwyczajnie trzeba zrobić ExecuteReader/ExecuteScalar. Choćby ze względu na wydajność w przypadku dużych ilości danych(np. raportów). Trzeba dopisać nowe procedury, być może dodać tabele/indeksy/kolumny.
ad c) Nie ma znaczenia, czy link prowadzi do /Home/12, /Home/Zbig12niew, czy /Home/23bjk24h3g4o23ueh23. Jeśli ktoś zdobędzie link to i tak dostanie zbiór danych.

a + c
Jeśli szyfrowanie będzie oparte o zmienną per user w sesji, to nie będzie można przesyłać linków innym, linki będą wygasać(brak ulubionych) i za każdym razem, gdy będziesz musiał wyświetlać dużą liczbę id, konieczne będzie zaszyfrowanie całego zbioru kluczowych/wrażliwych danych(a to też trwa).

Co Ty bredzisz? Pisałeś kiedykolwiek coś większego w MVC? Bo jakieś dziwne mechanizmy, zwłaszcza w punkcie "a" podsuwasz.

0
emfałsi napisał(a)

Co Ty bredzisz? Pisałeś kiedykolwiek coś większego w MVC? Bo jakieś dziwne mechanizmy, zwłaszcza w punkcie "a" podsuwasz.

Bądź łaskaw rozwinąć.
Jedyne co proponuję, to przeprowadzić autoryzację po stornie bazy. Wszystko inne to komentarz do postów powyżej.

0
j_s_r_n napisał(a)
emfałsi napisał(a)

Co Ty bredzisz? Pisałeś kiedykolwiek coś większego w MVC? Bo jakieś dziwne mechanizmy, zwłaszcza w punkcie "a" podsuwasz.

Bądź łaskaw rozwinąć.
Jedyne co proponuję, to przeprowadzić autoryzację po stornie bazy. Wszystko inne to komentarz do postów powyżej.

Zasugerowałeś, że ktoś posiadając tylko adres strony, bezproblemowo wejdzie na adres który posiada.

Czyli np. wchodzie w posiadanie adresu: /Admin/Users/Edit/32 - dajmy na to miejsce edycji uzytkownika o id 32.

Czy uważasz że jak ktoś wklei ten adres w przeglądarkę, to bez problemu pod niego wejdzie? Bo tak to zrozumiałem w tym co Ty napisałeś.

0
emfałsi napisał(a)
j_s_r_n napisał(a)
emfałsi napisał(a)

Co Ty bredzisz? Pisałeś kiedykolwiek coś większego w MVC? Bo jakieś dziwne mechanizmy, zwłaszcza w punkcie "a" podsuwasz.

Bądź łaskaw rozwinąć.
Jedyne co proponuję, to przeprowadzić autoryzację po stornie bazy. Wszystko inne to komentarz do postów powyżej.

Zasugerowałeś, że ktoś posiadając tylko adres strony, bezproblemowo wejdzie na adres który posiada.

Czyli np. wchodzie w posiadanie adresu: /Admin/Users/Edit/32 - dajmy na to miejsce edycji uzytkownika o id 32.

Czy uważasz że jak ktoś wklei ten adres w przeglądarkę, to bez problemu pod niego wejdzie? Bo tak to zrozumiałem w tym co Ty napisałeś.

W takim razie to nieporozumienie. Wejdzie o ile zostanie wpuszczony. Jeśli strona wymaga logowania, to najpierw zostanie przekierowany na stronę logowania, a po pomyślnym logowaniu wróci na /Admin/Users/Edit/32.
Z tego co zrozumiałem, problemu nie można załatwić samym logowaniem, ani rolami, bo w jednej tabeli znajdują się wiersze do których różni ludzie mają różne uprawnienia(np. Ja mogę oglądać/modyfikować tylko te, które sam stworzyłem).
Zatem po logowaniu trzeba sprawdzić, czy Ja mogę edytować Usera o id 32(bo niektórych mogę).
Wasiu do tej pory proponował, z tego co ja zrozumiałem:
a) przy wejściu na stronę /Admin/Users/ wpisanie do sesji wszystkich id zwróconych dla mnie z bazy, aby przy wejściu do /Admin/Users/Edit/32 sprawdzić czy w sesji jest id=32.
b) przy wejściu na /Admin/Users/Edit/32 wyciągnięcie wszystkich wierszy do których mam uprawnienia i sprawdzenie, czy id=32 się w nich zawiera(co jest czasochłonne).
c) zapisanie 32 w jakimś dziwnym formacie przed wyświetleniem w /Admin/Users/ i odszyfrowanie po wejściu na /Admin/Users/Edit/"32wDziwnymFormacie"

1 użytkowników online, w tym zalogowanych: 0, gości: 1