Moje pytanie dotyczy bezpieczeństwa JavaScript.
Wyobraź sobie system uwierzytelniania, w którym używasz środowiska JavaScript, takiego jak Backbone lub AngularJS , i potrzebujesz bezpiecznych punktów końcowych. To nie jest problem, ponieważ serwer zawsze ma ostatnie słowo i sprawdzi, czy masz uprawnienia do robienia tego, co chcesz.
Ale co, jeśli potrzebujesz trochę bezpieczeństwa bez angażowania serwera? Czy to jest możliwe?
Załóżmy na przykład, że masz system routingu po stronie klienta i chcesz chronić konkretną trasę dla zalogowanych użytkowników. Pingujesz więc serwer, pytając, czy możesz odwiedzić chronione trasy i kontynuujesz. Problem polega na tym, że podczas pingowania na serwer zapisujesz odpowiedź w zmiennej, więc przy następnym przejściu na prywatną trasę sprawdzi, czy jesteś już zalogowany (brak pingowania na serwer) i zależnie po odpowiedzi pójdzie, czy nie.
Jak łatwo jest zmodyfikować tę zmienną i uzyskać dostęp?
Moja wiedza na temat bezpieczeństwa (i JavaScript) nie jest dobra. Ale jeśli zmienna nie ma zasięgu globalnego i znajduje się w prywatnej części wzorca modułu, który ma tylko metody pobierające, ale nie ustawiające, nawet w takim przypadku, czy możesz to zhakować?
źródło
manipulate any part of the sight without long lines
strona vs widokOdpowiedzi:
Proszę przeczytać odpowiedź Joachima przed przeczytaniem tego. Omawia ogólne przyczyny luki w zabezpieczeniach po stronie klienta. A teraz sugestia, jak możesz obejść ten problem ...
Bezpieczny schemat komunikacji klient-serwer bez konieczności ręcznego uwierzytelniania na serwerze na każde żądanie:
Jesteś nadal pozwalając serwer mieć ostatnie słowo, a serwer nadal musi potwierdzić wszystko, co klient mówi, ale zdarza się przejrzysty.
Załóżmy protokół HTTPS , aby zapobiec atakom typu man-in-the-middle (MITMA).
Klient po raz pierwszy uzgadnia z serwerem, a serwer generuje klucz publiczny dla klienta i zachowuje klucz prywatny za pomocą asymetrycznego schematu szyfrowania. Klient przechowuje „publiczny” klucz serwera w lokalnej pamięci, zaszyfrowany bezpiecznym hasłem, którego nigdzie nie zapisujesz.
Klient jest teraz offline. Klient chce wykonywać zaufane działania. Klient wprowadza swoje hasło i pobiera klucz publiczny serwera.
Klient wykonuje teraz działania na podstawie swojej wiedzy o tych danych, a następnie szyfruje każdą akcję, którą wykonuje za pomocą klucza publicznego serwera dla tego klienta .
Gdy klient jest w trybie online, wysyła swój identyfikator klienta, a wszystkie wykonywane przez niego działania są wysyłane na serwer zaszyfrowany kluczem publicznym serwera.
Serwer odszyfrowuje akcje, a jeśli są w prawidłowym formacie, ufa, że pochodzą od klienta.
Uwaga:
Nigdzie nie możesz przechowywać hasła klienta, w przeciwnym razie osoba atakująca byłaby w stanie pobrać klucz i podpisać akcje jako własne. Bezpieczeństwo tego schematu zależy wyłącznie od integralności klucza generowanego przez serwer dla klienta. Klient nadal będzie musiał zostać uwierzytelniony na serwerze, gdy poprosi o ten klucz.
W rzeczywistości nadal polegasz na serwerze, a nie na kliencie. Każdą czynność wykonywaną przez klienta należy sprawdzić na serwerze.
Możliwe jest uruchamianie zewnętrznych skryptów w robotach sieciowych . Pamiętaj, że każde Twoje żądanie JSONP jest teraz znacznie większym problemem bezpieczeństwa. Musisz chronić klucz za wszelką cenę. Po utracie atakujący może podszyć się pod użytkownika.
Spełnia to Twoje żądanie, aby „nie pingować na serwer”. Atakujący nie może po prostu naśladować żądania HTTP z fałszywymi danymi, jeśli nie zna klucza.
Odpowiedź Joachima jest nadal poprawna . Nadal wykonujesz wszystkie uwierzytelnienia na serwerze . Jedyne, co tutaj zapisałeś, to konieczność każdorazowego sprawdzania hasła na serwerze. Teraz musisz zaangażować serwer tylko wtedy, gdy chcesz zatwierdzić lub pobrać zaktualizowane dane. Wszystko, co tutaj zrobiliśmy, to zapisanie zaufanego klucza po stronie klienta i poproszenie go o ponowne sprawdzenie.
Jest to dość powszechny schemat dla aplikacji jednostronicowych (na przykład w AngularJS).
Nazywam klucz publiczny serwera „publicznym” ze względu na to, co to oznacza w programach takich jak RSA , ale w rzeczywistości jest to poufna informacja w systemie i powinna być chroniona.
Nigdzie nie zachowałbym hasła w pamięci. Zmusiłbym użytkownika do przesyłania swojego hasła offline za każdym razem, gdy zaczyna on uruchamiać kod offline.
Nie rzucaj własną kryptografią - do uwierzytelniania używaj znanej biblioteki, takiej jak Stanford.
Weź tę radę taką, jaka jest . Przed uruchomieniem tego rodzaju uwierzytelniania w aplikacji o znaczeniu krytycznym dla biznesu skonsultuj się z ekspertem ds . Bezpieczeństwa . Jest to poważny problem, który jest zarówno bolesny, jak i łatwy do popełnienia błędu.
Bardzo ważne jest, aby żadne inne skrypty nie miały dostępu do strony. Oznacza to, że zezwalasz tylko zewnętrznym skryptom na pracę w sieci. Nie możesz ufać żadnym innym zewnętrznym skryptom, które mogłyby przechwycić twoje hasło, gdy użytkownik je wprowadzi.
Użyj pola hasła,
prompt
a nie wbudowanego, jeśli nie masz całkowitej pewności i nie odkładaj jego wykonania (to znaczy, nie powinno dojść do punktu, w którym zdarzenia mają do niego dostęp, ale tylko w kodzie synchronizacji). I tak naprawdę nie przechowuj hasła w zmiennej - znowu działa to tylko wtedy, gdy ufasz, że komputer użytkownika nie zostanie naruszony (chociaż to wszystko dotyczy również sprawdzania poprawności na serwerze).Chciałbym jeszcze raz dodać, że nadal nie ufamy klientowi . Nie możesz ufać samemu klientowi i myślę, że odpowiedź Joachima to ugruntowała. Zyskaliśmy jedynie wygodę, że nie musimy pingować serwera przed rozpoczęciem pracy.
Powiązany materiał:
źródło
window.prompt
metodę w celu przechwycenia frazy hasła lub uruchomienia własnego monitu (być może w ramach elementu iframe!). Pole hasła ma jeszcze jedną zaletę: znaki nie są wyświetlane.To proste: każdy mechanizm bezpieczeństwa, który polega na tym, że klient robi tylko to, co mu każesz, może zostać naruszony, gdy osoba atakująca ma kontrolę nad klientem.
Państwo może mieć kontrole bezpieczeństwa na kliencie, ale tylko skutecznie działać jako „cache” (w celu uniknięcia podejmowania kosztownych round-trip do serwera, jeśli klient już wie, że odpowiedź będzie „nie”).
Jeśli chcesz zachować informacje od zestawu użytkowników, upewnij się, że klient tych użytkowników nigdy nie dostanie się do tych informacji. Jeśli wyślesz te „tajne dane” wraz z instrukcjami ”, ale nie wyświetlaj ich”, wyłączenie kodu sprawdzającego to żądanie stanie się trywialne.
Jak widać, ta odpowiedź tak naprawdę nie wspomina o żadnych szczegółach dotyczących JavaScript / przeglądarki. To dlatego, że ta koncepcja jest taka sama, bez względu na to, jaki jest twój klient. Tak naprawdę nie ma znaczenia, że jest to gruby klient (tradycyjna aplikacja klient / serwer), oldschoolowa aplikacja internetowa lub aplikacja jednostronicowa z rozbudowanym skryptem JavaScript po stronie klienta.
Gdy Twoje dane opuszczą serwer, musisz założyć, że atakujący ma do nich pełny dostęp.
źródło
Społeczność graczy mówi: „ Klient jest w rękach wroga". Każdy kod działający poza bezpiecznym obszarem, takim jak serwer, jest podatny na atak. W najbardziej podstawowym scenariuszu jest podatny na to, że nie zostanie uruchomiony w pierwszej kolejności. To klient decyduje o uruchomieniu" kodu bezpieczeństwa ", a użytkownik może po prostu „zrezygnuj”. Podczas gdy w natywnym kodzie masz co najmniej automatyczne zaciemnianie w asemblerze i dodatkową warstwę ochrony przez fakt, że atakujący musi być dobrym programistą, aby nim manipulować, JS jest zwykle nieobsługiwany i jako zwykły tekst. Wszystko, czego potrzebujesz, aby przeprowadzić atak, to prymitywne narzędzia, takie jak serwer proxy i edytor tekstu. Atakujący będzie nadal potrzebował pewnego poziomu wiedzy na temat programowania, ale o wiele łatwiej jest zmodyfikować skrypt za pomocą dowolnego edytora tekstu niż wstrzyknąć kod do pliku wykonywalnego.
źródło
To nie jest kwestia włamania się do JavaScript. Gdybym chciał zaatakować twoją aplikację, użyłbym prywatnego serwera proxy, który pozwoliłby mi przechwytywać, modyfikować i odtwarzać ruch. Wygląda na to, że proponowany system zabezpieczeń nie obejmuje żadnych zabezpieczeń.
źródło
Mówiąc konkretnie o Angular:
Ochrona trasy po stronie klienta po prostu nie istnieje. Nawet jeśli „ukryjesz” przycisk do tej trasy, użytkownik zawsze może go wpisać, Angular narzeka, ale klient może to zakodować.
W pewnym momencie administrator będzie musiał poprosić serwer o dane potrzebne do renderowania widoku, jeśli użytkownik nie jest upoważniony do dostępu do tych danych, nie otrzyma ich, ponieważ chroniłeś te dane po stronie serwera , a Twoja aplikacja Angular powinna odpowiednio obsługiwać 401.
Jeśli próbujesz chronić nieprzetworzone dane, nie możesz po stronie klienta, jeśli chcesz, aby konkretny użytkownik mógł tylko przeglądać wspólne dane w określony sposób, utwórz „widoki” danych na serwerze zamiast wysyłać nieprzetworzone dane dla klienta i ich reorganizacja (powinieneś już to zrobić ze względu na wydajność).
Uwaga dodatkowa: nigdy nie powinno być żadnych wrażliwych elementów wbudowanych w szablony widoku, których zażąda Angular, po prostu nie rób tego. Jeśli z jakiegoś szalonego powodu istnieje, musisz chronić te szablony widoków po stronie serwera, tak jak gdybyś robił renderowanie po stronie serwera.
źródło