Jak zabezpieczyć system przed „głupotą” użytkowników?

Tworząc różnego rodzaju systemy, nie unikniemy interakcji z użytkownikami. Tylko co zrobić, aby zabezpieczyć się, przed ich umyślnymi i nieumyślnymi błędami?

Użytkownicy różnych systemów, często nie są świadomi popełnianych błędów. Często wprowadzają błędne dane z ignorancji, lenistwa, czy po prostu przez pomyłkę. Nie zawsze jesteśmy w stanie przewidzieć wszystkie przypadki, a tzw. testy na produkcji, często pokazują jak wielu scenariuszy, nie wzięliśmy pod uwagę, podczas projektowania systemu.

Często podczas początkowej fazy projektowania architektury systemów, omawiamy z klientami różne przypadki i staramy się ustalić poziomy krytyczności różnych problemów. Często z punktu widzenia biznesowego, nie opłaca się z góry przewidywać i zabezpieczać wszystkich możliwości wystąpienie problemów. Są elementy systemów, gdzie jak raz na jakiś czas coś źle zadziała, to nic się nie stanie. Z drugiej strony trzeba zidentyfikować krytyczne miejsca, gdzie nie może wystąpić żadne przekłamanie w danych.

Popularne błędy.

Błędy w formularzach.

Mając w systemie miejsce, w którym oczekujemy od klienta, wprowadzenia danych, musimy z góry założyć, że wprowadzi je błędnie.

Przykładowo, jeżeli mamy pole numeryczne, to użytkownik może z przyzwyczajenia wprowadzać tam różne dodatkowe znaki. Przykładowo, gdy chcemy, aby użytkownik podał numer telefonu, to jedna osoba wpisze liczby ciągiem, inna rozdzieli je spacjami, a ktoś inny rozdzieli grupy liczb myślnikami. Niektórzy podadzą numer telefonu z prefiksem kraju, inni bez niego. Z punktu widzenia zwykłego użytkownika jest to bez znaczenia. Natomiast z punktu widzenia programisty są to kompletnie różne dane, które często mogą zmienić zachowanie systemu.

Niektórzy użytkownicy próbują specjalnie wprowadzać błędne dane, aby zobaczyć, jak system się zachowa. Jeżeli system oczekuje dodatniej liczby całkowitej, to musimy być pewni, że ktoś wprowadzi liczbę ujemną, ktoś inny będzie próbował wprowadzić ułamek, a jeszcze ktoś inny zacznie wprowadzać tam tekst.

Mógłbym wymieniać bardzo długo różne inne tego typu przypadki, takie jak przesyłanie plików w niewłaściwym formacie, czy wprowadzanie różnych innych dziwnych rzeczy w formularze.

Błędy funkcjonalne.

Innym typem problemów, które bardzo często spotykamy, jest pośpieszne wywoływanie różnych funkcji przez użytkowników, bez zastanowienia się nad konsekwencjami.

Jeśli udostępnimy użytkownikom systemu usuwanie czegokolwiek, to na 100% będziemy mieli przez to problemy. Klient chce opcję usunięcia zbędnych zamówień? Ok, tylko przygotuj się na wiadomości z pytaniami, „Czy jednak to zamówienie można przywrócić?”, „Można jeszcze sprawdzić, jakie produkty były w tym usuniętym zamówieniu?”. Niestety niewiele dają ostrzeżenia i dodatkowe potwierdzenia. Klient chce mieć opcję usuwania produktów, to przygotuj się na konieczność ich przywracania.

Często spotykamy się z sytuacjami, gdy klient oczekuje funkcjonalności, np.: usuwania danych, które posiadają relacje z innymi elementami. Oczywiście jeżeli klient tego wymaga, to musimy dodać taką funkcjonalność. Przy normalnych projektach, powinniśmy się zabezpieczyć, przed utraceniem spójności danych, np.: gdy w innym miejscu systemu będziemy mieli odwołanie do skasowanego elementu. Jednak często przy nisko budżetowych projektach, właściciele decydują, aby nie zabezpieczać tego dokładnie, mówiąc, że będą pamiętali, aby nie usuwać tych elementów, jeżeli będą je wykorzystywać w innych miejscach. Ok, pamiętają przez pierwszy tydzień, może miesiąc, a później przez przypadek zapominają, albo mają nowego pracownika, któremu zapomnieli tego przekazać i mamy problem. Oczywiście później są pretensje, dlaczego to nie było zabezpieczone. W przypadku gdy mamy takie ustalenia spisane np.: na mailu to świetnie. Natomiast w przypadku gdy było to tylko ustalone ustnie na spotkaniu, to mamy słowo przeciwko słowu i kończy się zazwyczaj na tym, że musimy ten problem rozwiązać.

Metody walidacji danych.

W przypadku danych, otrzymywanych z typowych formularzy, możemy przeprowadzać różne rodzaje walidacji. Zawsze powinniśmy stosować wielopoziomowe walidacje i nie możemy ograniczać się tylko do jednego ich rodzaju.

Front-End’owa walidacja danych.

Przed tym jak dane trafią do naszego systemu, powinniśmy je sprawdzić po stronie formularza. Szczególnie istotne jest to przy systemach webowych, gdzie dane są wprowadzane w przeglądarce internetowe.

Standardowo jeżeli oznaczymy odpowiednie pola, odpowiednim typem danych, to sama przeglądarka przeprowadzi podstawową walidację. Jednak nie zawsze będzie to dokładne i wiarygodne. Często różne przeglądarki różnie interpretują różne typy pól formularzy. Dodatkowo wszystko, co jest wyświetlane w przeglądarce klienta, może być przez niego zmienione. Jeżeli np.: mamy pole numeryczne, to użytkownik, bez żadnego wysiłku może zmienić typ pola np.: na tekstowy.

Po stronie klienta możemy dopisać także własne walidatory, np.: wykorzystując skrypty js, które dokładniej sprawdzą dane przed ich wysłaniem. Odpowiednie skrypty mogą nawet wyświetlić podpowiedzi już podczas wprowadzania danych przez klienta.

Zalety

  • Walidacja odbywa się po stronie komputera klienta, więc nie obciąża nam serwera.
  • Jest bardziej przyjazna dla użytkownika.
  • Pozwala na skorygowanie danych już podczas ich wprowadzania.

Wady

  • Złośliwy użytkownik może łatwo oszukać tego typu walidację.
  • Nie zabezpieczy ona nas przed botami.

Pomimo tego, że ostatecznie nie możemy w pełni ufać tego typu walidacji, to nie powinniśmy z niej rezygnować. Walidacja Front-End’owa jest zazwyczaj bardziej przyjazna dla klientów, który nie chce kombinować z celowym wywołaniem błędu w systemie.

Back-End’owa walidacja danych.

Pomimo początkowej walidacji danych, niezbędna jest zawsze walidacja po stronie serwera.

W przypadku gdy dane zostaną już przesłane z formularza, np.: do kontrolera w systemie, to przed ich wykorzystaniem musimy zawsze bezwzględnie przeprowadzić analizę otrzymanych danych.

Poza wcześniej wymienionymi przypadkami celowej zmiany typu danych, po stronie serwera prawie na pewno natrafimy na przypadki prób włamania z wykorzystaniem np.: SQL injection. Natomiast w przypadku plików, powinniśmy spodziewać się prób przesłania skryptów wykonywalnych, czy innego złośliwego oprogramowania.

Tworząc oprogramowanie z wykorzystaniem nowoczesnych framework’ów typu np.: Laravel czy Symfony, mamy sprawę mocno ułatwioną. Tego typu framework’i posiadają już wiele wbudowanych mechanizmów walidacji danych, które możemy wykorzystać.

Zalety

  • Mamy pewność, że nie wystąpiła ingerencja w algorytmy walidacyjne.
  • Dobrze przeprowadzona walidacja, daje nam wysoki próg pewności poprawności danych.

Wady

  • Walidacja odbywa się po stronie serwera, więc wymaga mocy obliczeniowej naszej maszyny.

Pomimo bardzo wysokiej pewności, nigdy nie możemy także być w 100% pewni, że nie przeoczyliśmy jakiegoś przypadku i powinniśmy zastosować dodatkowe zabezpieczenia przed utratą spójności danych.

Inne metody zabezpieczeń.

Walidatory zabezpieczą nas przed błędnie wprowadzonymi danymi, jednak nie zabezpieczą nas np.: przed usunięciem istotnych danych. Pominę tutaj kwestię tego, że powinniśmy najpierw sprawdzić, czy użytkownik ma uprawnienia do usuwania danego typu danych. Co natomiast możemy zrobić gdy użytkownik, który ma odpowiednie uprawnienia, pomimo ostrzeżeń usunie istotne dane?

Soft delete.

Pierwszym ze sposobów jest zastosowanie mechanizmu soft delete. Czyli nie usuwamy żadnego rekordu z bazy danych, a jedynie oznaczamy dane jako usunięte.

Dzięki temu mechanizmowi, gdy klient zwróci się do nas z prośbą o pomoc, możemy łatwo przywrócić skasowane dane.

Wadą tego rozwiązania jest to, że dane z bazy nie znikają, więc robi się ich coraz więcej. Jeżeli intencją użytkownika było odchudzenie bazy danych, to pomimo pozornego usunięcia danych, będą one dalej znajdowały się w bazie danych.

Przy tego typu rozwiązaniach, powinniśmy zaprojektować mechanizm odpowiadający za czyszczenia bazy. Może on np.: po miesiącu od oznaczenia danych jako usunięte, kasować je na twardo. Mechanizm taki, może także np.: przenosić dane do tabeli typu archive, która zajmuje mniej miejsca, ale umożliwia awaryjny wgląd w skasowane dane.

Zabezpieczenia bazodanowe.

Pomimo różnych metod walidacji, powinniśmy przemyśleć także architekturę samej bazy danych.

Przykładowo przy głównych typach danych, powinniśmy ustawić odpowiednio relacje, aby np.: uniemożliwiły usunięcie danych, jeżeli dany element został użyty w innym miejscu. Zdarzają się także przypadki, że bardziej pożądane jest, aby kasowane były wszystkie powiązane elementy, w celu uniknięcia utraty spójności danych.

Poza samymi relacjami powinniśmy odpowiednio ustawić typy danych poszczególnych kolumn w tabelach. Tak, aby dokładnie odpowiadały naszym potrzebom i zminimalizowały ryzyko błędów.

Tego typu zabezpieczenia są najbardziej elementarne. Baza danych, w momencie wystąpienia błędu, np.: poprzez zły typ danych, który próbujemy zapisać w danej kolumnie, wywoła błąd i nie pozwoli na zapisanie danych. Powinniśmy pamiętać, o tym, że musimy obsłużyć taki przypadek po stronie systemu, inaczej użytkownik końcowy może zobaczyć błąd 500 serwera.

Edukacja użytkowników.

Najbardziej kosztowna jest zawsze edukacja użytkowników, jednak często jest niezbędna. Tłumaczenie czego nie robić, a co robić, jest bardzo czasochłonne, dlatego nie powinniśmy na to stawiać. Przede wszystkim powinniśmy zastosować wielopoziomowe zabezpieczenia programistyczne.

Oczywiście podstawowe wytyczne i instrukcje musimy przekazać użytkownikom. Jednak nigdy nie wymusimy na nich tego, aby trzymali się oni naszych wskazówek.

Żadnych ustnych ustaleń.

Na koniec, należy pamiętać o tym, że z klientami nie powinniśmy nigdy nic ustalać ustnie. Szczególnie przy projektach z niskim budżetem. Często tak jak wspominałem wyżej, nie chcą oni, aby za bardzo wchodzić w zabezpieczenia, bo zależy dla nich tylko na podstawowych funkcjonalnościach. Niestety w razie jakiegoś błędu, to na nas skupi się ich uwaga w pierwszej kolejności. Dlatego nawet jeżeli ustalamy takie szczegóły na spotkaniu czy telefonicznie, to powinniśmy przesłać podsumowanie takiej rozmowy na adres e-mail klienta, z prośbą o potwierdzenie. Dzięki temu unikniemy w przyszłości nieprzyjemnych sytuacji, w których będzie tylko nasze słowo, przeciwko słowu klienta.

Podsumowanie.

Podsumowując, nie powinniśmy zapominać o zabezpieczeniu naszego systemu przed różnymi nietypowymi sytuacjami. Tworząc system, powinniśmy także stosować wielopoziomowe metody walidacji danych. Powinniśmy także przemyśleć jak zabezpieczyć się, przed przypadkowym usunięciem danych przez użytkownika.

Tak naprawdę, to tylko niewielka część tego, z czym mamy do czynienia na co dzień.


Chcesz otrzymywać ciekawe informacje?

Bezpieczeństwo

Nowy komentarz

Twój adres e-mail nie zostanie opublikowany.

Poprzednie
Jak zabezpieczyć system przed „głupotą” użytkowników?
Następny artykuł
Tworzenie backupów stron i sklepów