How to protect software and data?

5 january 2023
Jakub Rojek Jakub Rojek
Photo provided by Pixabay (https://www.pexels.com/pl-pl/zdjecie/impas-z-kluczem-w-otworze-279810/)
Categories: Industry, For clients, IT fundamentals

Systemy informatyczne pod kątem projektu składają się z części funkcjonalnej oraz niefunkcjonalnej. Oba aspekty są opisywane przez różne wymagania, natomiast dzisiaj bardziej będzie interesował nas ten drugi obszar. Jak pewnie się domyślacie, o ile pewne czynniki jakościowe są bardzo specyficzne dla różnych aplikacji, o tyle są dziedziny, na których (poza szczególnymi przypadkami) zależy wszystkim. Jednym z nich jest bezpieczeństwo rozumiane na dwa sposoby - safety (ochrona przed nieumyślnymi działaniami i zjawiskami) oraz security (ochrona przed atakami).

Tematy związane z bezpieczeństwem zyskały w ostatnich latach na popularności i nie bez powodu - coraz więcej danych jest zdigitalizowanych i umieszczonych na przeróżnych serwerach, w tym w chmurach. W sieci przechowujemy coraz więcej danych, zarówno tymczasowych, nieistotnych, wręcz "rozrywkowych", jak i osobistych czy wręcz krytycznych. I nie mamy tutaj na myśli tylko personaliów, ale także dane finansowe, prawne, historię naszych akcji czy hasła, których wyciek mógłby nam poważnie zaszkodzić i zwykle szkodzi. Nie od dzisiaj słyszymy o tym, że na "rynku" pojawiła się baza danych z jakiegoś popularnego serwisu lub komuś włamano się na konto.

Oczywiście, istnieją specjaliści, którzy zajmują się tylko i wyłącznie kwestiami zabezpieczeń oprogramowania i chwała im za to. Jest to działalność istotna nie tylko dla sfery IT, ale także (a może i przede wszystkim) dla zwykłych ludzi, ogółu użytkowników globalnej sieci. Dodatkowo, oprócz zwykłej pracy dla biznesu, eksperci mają też czas prowadzić popularne strony i blogi, w których tłumaczą różne ataki oraz sposoby ochrony - duża część z Was zna Niebezpiecznika, Zaufaną Trzecią Stronę czy Sekuraka, a jeśli nie, to warto poznać, gdyż przedstawiają materiały w sposób jednocześnie techniczny, ale też "zjadliwy" dla przeciętnego internauty.

Jednak nie zawsze trzeba radzić sobie z atakiem - istnieje znana zasada "lepiej zapobiegać niż leczyć" i działa ona także w informatyce. Do dyspozycji programistów i administratorów jest wiele technik, które pomagają wzmocnić defensywę, a czasem sprawić, że ewentualnie wykradzione informacje nie są użyteczne dla atakującego. Co więcej, te techniki w większości nie są trudne w użyciu i bardzo często podstawowe zabezpieczenia są wręcz integralną częścią różnych frameworków - niektórych środków ochrony używa się machinalnie, przy innych trzeba się nieco napracować. Chcielibyśmy dzisiaj je przedstawić, aby też pokazać osobom zmartwionym potencjalną koniecznością wydania większej sumy pieniędzy na zabezpieczenia, jakim podstawowym orężem dysponują software house'y.

Haszowanie haseł

Zacznijmy od rzeczy podstawowej i ważnej dla każdego użytkownika Internetu - hasła muszą być gdzieś zapisywane i dzieje się to zazwyczaj w bazie danych. Można zatem mieć wątpliwości co do tego, co się dzieje w momencie, kiedy ktoś do tej bazy danych wejdzie (bezpośrednio lub przez np. panel administratora) lub wręcz ją pobierze. Takie rzeczy już się zdarzały i niejednokrotnie pojawiały się wówczas rekomendacje, aby zmienić hasło używane w serwisie. Natomiast przy odpowiedniej technice prawdopodobieństwo, że taki wyciek spowoduje "skompromitowanie" (specjalnie użyłem kalki z języka angielskiego) akurat naszego hasła jest dość małe. Dlaczego?

Od dawna hasła w bazie danych zapisywane są w formie haszowanej, co oznacza, że dla każdego ciągu znaków odpowiedni algorytm generuje określony skrót. W efekcie, gdy użytkownik wpisuje hasło "Abcd1234", to faktycznie jest ono przesyłane przez przeglądarkę do serwera (ważne, aby odbywało się to przez HTTPS, do czego jeszcze wrócimy), ale tam może zostać zamienione na taką postać (gdy używany jest Bcrypt z 13 rundami):

$2a$13$sOa6zWfUOVJD6V.1QcB9s.2umv.B8LbR9/wjWQ5Ind3t/QBGuZOGe

I dopiero w takiej formie jest zapisywane w bazie danych, a porównywanie ciągów znaków przy logowaniu odbywa się na zasadzie przyrównania hasza z bazy do hasza z wpisanego hasła. Co więcej, ten skrót jest jednokierunkowy - nie można odwrócić operacji i pobrać z niego oryginalnego hasła. Algorytmów tego typu jest dużo (BCrypt, SHA, MD5 itd.) i różnią się między sobą poziomem zabezpieczenia oraz wydajnością działania, jednak w tym przypadku różnice szybkościowe są na tyle małe, że warto korzystać z mocniejszej ochrony, co w większości portali ma miejsce. To też odpowiada na pytanie "czy administrator zobaczy moje hasło w panelu administratora?". Otóż nie - nie zobaczy, gdyż jedyne, co może ujrzeć, to rzeczony i niedający się zdekonspirować hasz. Może też zmienić hasło na inne, jednak ponownie zostanie ono zahaszowane i niemożliwe później do odczytania.

Oczywiście, teoretycznie nadal istnieje możliwość odgadnięcia hasła poprzez sukcesywne haszowanie różnych ciągów znaków i sprawdzanie ich z haszem uzyskanym z bazy danych. Jednak w praktyce może to trwać bardzo długo (wręcz nieopłacalnie długo), w czym pomaga ustawianie haseł długich i o dużym poziomie skomplikowania (aczkolwiek w którymś momencie staje się to kulą u nogi, o ile nie korzystamy z menedżerów haseł). Każdy dodatkowy znak to dodatkowe godziny, dni, a nawet lata potrzebne do złamania danego ciągu znaków. Gra jest zatem warta świeczki - ustawiajmy odpowiednio trudne i długie hasła.

Jako ciekawostkę można też podać fakt, że niektóre serwisy całkowicie zrezygnowały z konieczności zapamiętania haseł. Zamiast tego logowanie następuje poprzez podanie swojego adresu e-mail oraz późniejszego odczytania krótkoterminowego kodu z przesłanej wiadomości. W ten sposób działa (lub działały) np. usługa serverlessowa Vercel (znana kiedyś pod adresem now.sh), a także portal pracy SOLID.jobs.

Uwierzytelnianie i autoryzacja

Dla porządku warto wspomnieć o tym, co doskonale znamy z praktyki, ale niekoniecznie z terminów. Uwierzytelnianie (ang. authentication i przez to mylnie po polsku nazywane "autentykacją" - proszę, nie mówcie tak) to proces potwierdzania, że dana osoba jest tą, za którą się podaje. Z kolei autoryzacja (ang. authorization) to weryfikacja, czy dany użytkownik ma dostęp do określonego zasobu. Przekładając to na język praktyczny - gdy logujemy się do Facebooka, to jesteśmy poddawani uwierzytelnianiu (sprawdzana jest zgodność naszego hasła oraz adresu e-mail z informacjami zapisanymi w bazie). Gdy później chcemy zobaczyć posty zamkniętej grupy naszego rocznika na uczelni, to musimy przejść autoryzację (a więc serwis musi sprawdzić, czy mamy prawo do wyświetlenia lub nawet umieszczania postów na tej grupie).

Oczywiście, te podstawowe techniki pozwalają ukrywać określone dane przed niepowołanym dostępem i są tak naturalne, że wręcz trudno sobie wyobrazić bez nich przechowywanie mniej niewinnych informacji. Jednak sam proces uwierzytelnienia jest tutaj krytyczny, dlatego istnieją różne formy jego przeprowadzania. Nie zawsze serwisy bazują tylko na samym loginie i haśle - dodatkowe metody mogą objąć:

  • wpisanie kodu CAPTCHA lub np. wskazywanie zdjęć - rozpoznawanie robotów usiłujących włamać się na dane konto,
  • wpisanie kodu przesłanego na adres e-mail - opisane wyżej,
  • wpisanie kodu z SMS-a lub z aplikacji w rodzaju Google Authenticator - dodatkowe potwierdzenie tożsamości.

Punkt wymieniony jako ostatni to tzw. uwierzytelnianie dwuskładnikowe (2FA) i poleca się je włączyć wszędzie tam, gdzie jest możliwe. Dzięki temu zwiększamy pewność, że jeśli ktokolwiek loguje się na nasze konto, to jesteśmy to my sami. Chyba że zgubiliśmy nasz telefon, ale to problem innego rodzaju.

Uwierzytelnianie przez klucz SSH

Wspomnieliśmy o tym, że nie zawsze hasło jest wystarczającym rozwiązaniem. Dzieje się tak dlatego, że zawsze można je złamać (nawet jeśli trwa to bardzo długo), a co więcej - niekiedy logowanie jest tak czeste, że konieczność wpisywania długiego hasła za każdym razem jest dodatkowym obciążeniem. Dlatego w bardziej technicznych usługach kluczowe staje się wykorzystanie kluczy SSH.

W dużym skrócie jest to para plików zawierających bardzo długie, pasujące do siebie ciągi znaków, stanowiące część prywatną oraz publiczną. Dzięki temu, umieszczenie klucza publicznego w danym serwisie spowoduje, że aby się zalogować, użytkownik musi użyć (i mieć na dysku) odpowiedni klucz prywatny. To jak magiczny artefakt z filmów fantasy, gdzie dwie pasujące do siebie części pozwalają otworzyć konkretne wrota. W przypadku informatyki ten sposób uwierzytelnienia wykorzystuje się często do korzystania z repozytoriów Gita, a więc miejsca, gdzie znajduje się kod źródłowy naszego systemu - nie tylko nasza własność intelektualna, ale też czasami różne dalsze dane uwierzytelniające i klucze API, z których korzysta sama aplikacja.

Jednak równie często klucze SSH wykorzystuje się przy logowaniu na same serwery, do których zabezpieczenie dostępu jest jedną z kluczowych działań administratora. Dzięki temu zyskujemy nie tylko wygodę, ale też dodatkowe potwierdzenie, że użytkownik jest tym, za kogo się podaje (chyba że ktoś włamie się bezpośrednio na jego komputer).

Ochrona przed atakami SQL Injection i Cross-Site Scripting (XSS)

Obie te techniki ataków mają swoje stałe miejsce w opisach najczęstszych zagrożeń dla stron internetowych. Na szczęście, dzięki temu przez lata wypracowano techniki, z których programiści korzystają wręcz często nieświadomie, a które w większości zduszają taką ofensywę w zarodku. Mowa tutaj o wykorzystaniu bibliotek ORM (mapowań obiektowo-relacyjnych) przy korzystaniu z bazy danych, tzw. bindowaniu parametrów w zapytaniach SQL oraz "enkodowanie" wyświetlanych tekstów w celu pozbycia się złośliwych skryptów JavaScript.

Oczywiście, samo użycie frameworka nie rozwiązuje każdego problemu - niekiedy konieczne jest dostosowanie zabezpieczenia do sytuacji lub zwrócenie większej uwagi na to, aby wygoda programowania nie przysłoniła potencjalnych problemów z zabezpieczeniami. W każdym razie, dzięki rozwojowi narzędzi programistycznych ten problem został w dużym stopniu ograniczony.

Strona internetowa z certyfikatem SSL

Certyfikaty SSL pozwalają udostępniać zasoby w sieci nie poprzez nieszyfrowany protokół HTTP, ale poprzez szyfrowany HTTPS. Co to oznacza? Tyle, że jeśli ktoś spróbuje podsłuchać transmisję (w tym także wysyłane hasło do logowania) między komputerem użytkownika a serwerem, to przechwyci dane nie do odczytania bez odpowiedniego klucza, a tego klucza nie posiada, gdyż ma go tylko użytkownik i serwer. Oczywiście, kluczowy w tym jest odpowiednio wiarygodny certyfikat oraz uwaga przy jego sprawdzaniu. Tym niemniej, udostępnianie stron przez HTTPS nigdy nie było tak proste, jak obecnie i w większosci wypadków jest to warunek konieczny serwisu dla zainteresowania sobą użytkowników, ale także wyszukiwarek.

Dostęp do serwera przez VPN i ograniczanie widoczności urządzeń

Wyżej pisaliśmy o dostępie do serwera przez klucz SSH, jednak warto zauważyć, że sama możliwość uzyskania dostępu do serwera z dowolnego miejsca na świecie jest może i wygodna, ale budzi wątpliwości z punktu widzenia bezpieczeństwa. Dlatego w przypadku serwerów przygotowywanych indywidualnie na zamówienie i utrzymywanych przez konkretną firmę, czasami czynione są dodatkowe zabezpieczenia.

Może to być dostęp wyłącznie z konkretnych adresów IP, co jest proste, ale niekiedy niewystarczające, zwłaszcza jeśli nie wszyscy programiści łączą się z lokalizacji, w których dostępne jest stałe IP. Dlatego dużą popularnością cieszy się ustawienie połączenia VPN, które polega najpierw na wykorzystaniu serwera-bramy, z którego następnie możliwe jest dotarcie do docelowej maszyny lub innych elementów infrastruktury. Takie połączenie jest możliwe przez odpowiednie programy (np. OpenVPN) oraz po udostępnieniu odpowiedniej konfiguracji i konta ze strony administratora.

Zresztą, nie tylko do serwera może być ograniczony dostęp. Również inne komponenty mogą być ukryte przed publicznym dostępem. Jest to praktyktowane np. dla baz danych, do których wejście jest możliwe wyłącznie z poziomu innej, z góry określonej platformy. Także w przypadku wielu uslug backendowych można ukryć pewne komponenty przez dostępem z zewnątrz i wskazać konkretny inny serwis jako jedyne możliwe źródło.

Te wszystkie działania mogą zostać przeprowadzone przez administratorów, przynajmniej w środowiskach zamkniętych, czyli usługach świadczonych indywidualnie, na zamówienie. W przypadku serwerów "gotowych" oferowanych masowo przez firmy, zwykle takie dodatkowe zabezpieczenia są albo niemożliwe, albo ograniczone. Nie należy jednak tym się zrażać i zawsze warto zapytać o odpowiednią kwestię pomoc techniczną.

CORS oraz CSP

Jeśli już mowa o ograniczaniu dostępu, to w większości technologii możliwe do zdefiniowania są reguły CORS (ang. Cross-Origin Resource Sharing). W skrócie, pozwalają one na ustalenie dostępu do backendu wyłącznie z określonych źródeł. Przekładając to na praktykę, dzięki temu możliwe jest ukrycie usług backendowych przed ich wywołaniem z dowolnej strony lub programu, co pomaga w zabezpieczeniu przed np. odtwarzaniem w ten sposób poruszania się po zasobach witryny dzięki wysyłaniu konkretnych żądań HTTP (co czasem leży w zainteresowaniu osób, które nie mogą rozwiązać swojego zadania za pomocą scrapera).

Z kolei CSP (ang. Content Security Policy) jest techniką pozwalającą na ładowanie zasobów na samej stronie tylko z określonych miejsc. W ten sposób można nie pozwolić na wczytywanie obrazków czy skryptów z innych lokalizacji niż konkretna (najczęściej z domeny, na której znajduje się portal). Jest to technika będąca w zasięgu możliwości programistów, choć zazwyczaj powinna zostać skonsultowana z osobami zajmującymi się cyberbezpieczeństwem i należy przyłożyć szczególną uwagę do tego, aby dodatkowe zabezpieczenia nie spowodowały braku możliwości komfortowego korzystania ze strony. Warto też pamiętać, że nie jest to metoda, która bezpośrednio chroni nasze dane - bardziej chroni nas przed możliwością ataku, który w konsekwencji mógłby wykraść dane.

Regularne tworzenie kopii zapasowych

Na koniec klasyczna metoda, ale jakże często zapominana przez osoby opiekujące się daną usługą. Niekiedy celem ataku nie jest wykradzenie danych lub uzyskanie do nich dostępu, a jedynie ich zniszczenie. Należy też mieć na uwadze, że sytuacje, w których użytkownicy omyłkowo usuną niezbędne im informacje lub nastąpią jakieś komplikacje przy wdrożeniu nowej wersji na serwer, nie są aż tak rzadkie, jak mogłoby się wydawać. Z tego powodu i dla zwyczajnego spokoju ducha w przypadku np. awarii, warto tworzyć regularne kopie zapasowe bazy danych i plików.

Można to robić zarówno ręcznie i co jakiś czas wywoływać określony program na serwerze, ale także zdać się na programy automatyzujące ten proces, jak np. BorgBackup. Wszystko zależy od możliwości technicznych na serwerze, kompetencji osób (jest to raczej "działka" administratora) oraz poziomu poufności danych.

Podsumowanie

Jak widać, niektóre techniki zabezpieczania oprogramowania są dość naturalne i niekiedy dostępne "w pakiecie" razem ze stosowanymi silnikami i bibliotekami. Z drugiej strony, wiele aspektów jest po stronie administratorów mających pieczę nad serwerem i potrafiących zarządzać konfiguracją w taki sposób, aby możliwy był nie tylko wygodny dostęp do maszyny oraz bazy danych przez programistów, ale także krytyczne dane zostały ukryte przed niepowołanym dostępem, nawet przypadkowym. Oczywiście, portale o dużym poziomie zaufania lub bardzo popularne wymagają dodatkowych środków ostrożności oraz bardziej zaostrzonej polityki związanej np. z regułami haseł. Tym niemniej, jeśli do tej pory baliście się, że Wasze hasła są dostępne praktycznie dla każdego, to uspokajamy - uzyskanie ich jest dużo trudniejsze niż się wydaje, o ile programiści zastosują podstawowe środki ostrożności, porównywane np. z zamykaniem drzwi na klucz przy wychodzeniu z domu.

Pozdrawiam i dziękuję - Jakub Rojek.

We like to write, even a lot, but on a daily basis we develop web and mobile applications. Check some of the programs we have made.

About author

Jakub Rojek

Lead programmer and co-owner of Wilda Software, with many years of experience in software creation and development, but also in writing texts for various blogs. A trained analyst and IT systems architect. At the same time he is a graduate of Poznan University of Technology and occasionally teaches at this university. In his free time, he enjoys playing video games (mainly card games), reading books, watching american football and e-sport, discovering heavier music, and pointing out other people's language mistakes.

Jakub Rojek