Trzynaście zasad tworzenia bezpiecznych aplikacji Java

Bezpieczeństwo jest jednym z najbardziej złożonych, szerokich i ważnych aspektów tworzenia oprogramowania. Bezpieczeństwo oprogramowania jest również często pomijane lub upraszczane do zaledwie kilku drobnych poprawek pod koniec cyklu rozwoju. Wyniki widzimy w corocznej liście największych naruszeń bezpieczeństwa danych, która w 2019 roku wyniosła ponad 3 miliardy ujawnionych rekordów. Jeśli może się to przytrafić Capital One, może się to przytrafić tobie.

Dobra wiadomość jest taka, że ​​Java to od dawna platforma programistyczna z wieloma wbudowanymi funkcjami bezpieczeństwa. Pakiet Java Security przeszedł intensywne testy bojowe i jest często aktualizowany pod kątem nowych luk w zabezpieczeniach. Nowszy Java EE Security API, wydany we wrześniu 2017 r., Usuwa luki w chmurze i architekturach mikrousług. Ekosystem Java obejmuje również szeroką gamę narzędzi do profilowania i raportowania problemów z bezpieczeństwem. 

Ale nawet przy solidnej platformie programistycznej ważne jest, aby zachować czujność. Tworzenie aplikacji to złożone przedsięwzięcie, a luki w zabezpieczeniach mogą ukrywać się w szumie tła. Powinieneś myśleć o bezpieczeństwie na każdym etapie tworzenia aplikacji, od funkcji języka na poziomie klasy po autoryzację punktu końcowego API.

Poniższe podstawowe zasady stanowią dobrą podstawę do tworzenia bezpieczniejszych aplikacji Java.

Reguła bezpieczeństwa Java nr 1: pisz czysty, mocny kod Java

Luki w zabezpieczeniach uwielbiają ukrywać się w złożoności, więc staraj się, aby Twój kod był jak najprostszy bez poświęcania funkcjonalności. Korzystanie ze sprawdzonych zasad projektowania, takich jak DRY (nie powtarzaj się), pomoże Ci napisać kod, który będzie łatwiejszy do sprawdzenia pod kątem problemów.  

Zawsze ujawniaj jak najmniej informacji w swoim kodzie. Ukrywanie szczegółów implementacji obsługuje kod, który jest zarówno łatwy w utrzymaniu, jak i bezpieczny. Te trzy wskazówki pomogą Ci napisać bezpieczny kod Java:

  • Dobrze wykorzystaj modyfikatory dostępu Javy . Wiedza o tym, jak zadeklarować różne poziomy dostępu do klas, metod i ich atrybutów, znacznie przyczyni się do ochrony Twojego kodu. Wszystko, co można uczynić prywatnym, powinno być prywatne. 
  • Unikaj refleksji i introspekcji . Istnieją przypadki, w których takie zaawansowane techniki są warte, ale w większości przypadków należy ich unikać. Korzystanie z odbicia eliminuje silne pisanie, które może wprowadzić słabe punkty i niestabilność kodu. Porównywanie nazw klas jako ciągów jest podatne na błędy i może łatwo prowadzić do kolizji przestrzeni nazw.
  • Zawsze definiuj możliwie najmniejsze możliwe powierzchnie API i interfejsów . Odłącz komponenty i pozwól im współdziałać na jak najmniejszym obszarze. Nawet jeśli jeden obszar Twojej aplikacji zostanie zainfekowany naruszeniem, inne będą bezpieczne. 

Reguła bezpieczeństwa Java nr 2: Unikaj serializacji

To kolejna wskazówka dotycząca kodowania, ale jest wystarczająco ważna, aby być samodzielną zasadą. Serializacja pobiera zdalne dane wejściowe i przekształca je w w pełni wyposażony obiekt. Eliminuje konstruktory i modyfikatory dostępu, a strumień nieznanych danych staje się działającym kodem w JVM. W rezultacie serializacja Java jest głęboko i nieodłącznie niebezpieczna.

Koniec serializacji Java

Jeśli nie słyszałeś, Oracle ma długoterminowe plany usunięcia serializacji z Javy. Mark Reinhold, główny architekt grupy platform Java w Oracle, powiedział, że jego zdaniem co najmniej jedna trzecia wszystkich luk w Javie dotyczy serializacji.

O ile to możliwe, unikaj serializacji / deserializacji w kodzie Java. Zamiast tego rozważ użycie formatu serializacji, takiego jak JSON lub YAML. Nigdy, przenigdy nie ujawniaj niezabezpieczonego punktu końcowego sieci, który odbiera strumień serializacji i działa na jego podstawie. To nic innego jak powitalna mata na chaos.

Reguła bezpieczeństwa Java nr 3: nigdy nie ujawniaj niezaszyfrowanych poświadczeń ani informacji umożliwiających identyfikację

Trudno w to uwierzyć, ale ten możliwy do uniknięcia błąd powoduje ból rok po roku.

Gdy użytkownik wprowadza hasło do przeglądarki, jest ono wysyłane jako zwykły tekst na Twój serwer. To powinien być ostatni raz, kiedy ujrzy światło dzienne. Państwo musi szyfrować hasła poprzez jednokierunkową Cypher przed utrzymujących je do bazy danych, a następnie zrobić to ponownie, gdy porównując przeciwko tej wartości.

Zasady dotyczące haseł dotyczą wszystkich danych osobowych (PII): kart kredytowych, numerów PESEL itp. Wszelkie dane osobowe powierzone Twojej aplikacji powinny być traktowane z najwyższą starannością.

Niezaszyfrowane poświadczenia lub PII w bazie danych to ziejąca luka w zabezpieczeniach, która czeka na odkrycie przez atakującego. Podobnie, nigdy nie zapisuj surowych danych uwierzytelniających w dzienniku ani nie przesyłaj w inny sposób do pliku lub sieci. Zamiast tego utwórz solony skrót dla swoich haseł. Pamiętaj, aby przeprowadzić badania i użyć zalecanego algorytmu haszującego.

Przeskakując do zasady nr 4: zawsze używaj biblioteki do szyfrowania; nie tocz swoje własne.

Reguła bezpieczeństwa Java nr 4: używaj znanych i przetestowanych bibliotek

Naciesz oczy tym pytaniem i odpowiedzią na temat zmiany własnego algorytmu bezpieczeństwa. Lekcja tl; dr brzmi: używaj znanych, niezawodnych bibliotek i frameworków, kiedy tylko jest to możliwe. Dotyczy to całego spektrum, od haszowania haseł po autoryzację REST API.

Na szczęście Java i jej ekosystem mają tu swoje wsparcie. Jeśli chodzi o bezpieczeństwo aplikacji, Spring Security jest de facto standardem. Oferuje szeroki zakres opcji i elastyczność dostosowaną do dowolnej architektury aplikacji, a także obejmuje szereg podejść do zabezpieczeń.

Twoim pierwszym odruchem w walce z bezpieczeństwem powinno być zbadanie sprawy. Zapoznaj się z najlepszymi praktykami, a następnie dowiedz się, jaka biblioteka zaimplementuje te praktyki. Na przykład, jeśli chcesz używać tokenów sieciowych JSON do zarządzania uwierzytelnianiem i autoryzacją, spójrz na bibliotekę Java, która hermetyzuje JWT, a następnie dowiedz się, jak zintegrować to z Spring Security.

Nawet przy użyciu niezawodnego narzędzia dość łatwo jest zmylić autoryzację i uwierzytelnianie. Pamiętaj, aby poruszać się powoli i dokładnie sprawdzać wszystko, co robisz.

Reguła bezpieczeństwa Java nr 5: miej paranoję na temat zewnętrznych danych wejściowych

Niezależnie od tego, czy pochodzi to od użytkownika wpisującego w formularz, magazyn danych czy zdalny interfejs API, nigdy nie ufaj zewnętrznym wejściom.

Wstrzykiwanie SQL i skrypty między lokacjami (XSS) to tylko najbardziej znane ataki, które mogą wynikać z niewłaściwej obsługi zewnętrznych danych wejściowych. Mniej znanym przykładem - jednym z wielu - jest „atak miliarda śmiechu”, w którym rozszerzenie jednostek XML może spowodować atak typu Denial of Service.

Za każdym razem, gdy otrzymujesz dane wejściowe, należy je sprawdzić pod względem poczytalności i odkazić. Dotyczy to zwłaszcza wszystkiego, co może zostać przedstawione innemu narzędziu lub systemowi w celu przetworzenia. Na przykład, jeśli coś może skończyć się jako argument dla wiersza poleceń systemu operacyjnego: uwaga!

Specjalną i dobrze znaną instancją jest iniekcja SQL, którą omówiono w następnej regule.

Reguła bezpieczeństwa Java nr 6: Zawsze używaj przygotowanych instrukcji do obsługi parametrów SQL

Za każdym razem, gdy tworzysz instrukcję SQL, ryzykujesz interpolacją fragmentu kodu wykonywalnego.

Wiedząc o tym, dobrze jest zawsze używać klasy java.sql.PreparedStatement do tworzenia kodu SQL. Podobne udogodnienia istnieją dla sklepów NoSQL, takich jak MongoDB. Jeśli używasz warstwy ORM, implementacja użyje PreparedStatementdla ciebie s pod maską.

Reguła bezpieczeństwa Java nr 7: Nie ujawniaj implementacji za pomocą komunikatów o błędach

Komunikaty o błędach w środowisku produkcyjnym mogą być dobrym źródłem informacji dla atakujących. Zwłaszcza stosy śladów mogą ujawniać informacje o używanej technologii i sposobie jej używania. Unikaj ujawniania śladów stosu użytkownikom końcowym.

Do tej kategorii należą również alerty dotyczące nieudanego logowania. Ogólnie przyjmuje się, że komunikat o błędzie powinien być podawany jako „Logowanie nie powiodło się” zamiast „Nie znaleziono tego użytkownika” lub „Nieprawidłowe hasło”. Oferuj jak najmniej pomocy potencjalnym niecnym użytkownikom.

W idealnym przypadku komunikaty o błędach nie powinny ujawniać stosu technologii bazowej dla aplikacji. Utrzymuj te informacje jak najbardziej nieprzejrzyste.

Zasada bezpieczeństwa Java nr 8: Aktualizuj aktualizacje zabezpieczeń

Od 2019 r. Firma Oracle wdrożyła nowy schemat licencjonowania i harmonogram wydań oprogramowania Java. Niestety dla programistów, nowa kadencja wydania nie ułatwia sprawy. Niemniej jednak jesteś odpowiedzialny za częste sprawdzanie aktualizacji zabezpieczeń i stosowanie ich w środowisku JRE i JDK.

Upewnij się, że wiesz, jakie krytyczne poprawki są dostępne, regularnie sprawdzając stronę główną Oracle pod kątem alertów bezpieczeństwa. Co kwartał Oracle dostarcza automatyczną aktualizację poprawek do aktualnej wersji LTS (długoterminowego wsparcia) języka Java. Problem polega na tym, że ta poprawka jest dostępna tylko wtedy, gdy płacisz za licencję wsparcia Java.

Jeśli Twoja organizacja płaci za taką licencję, postępuj zgodnie z trasą automatycznej aktualizacji. Jeśli nie, prawdopodobnie używasz OpenJDK i będziesz musiał sam wykonać łatkę. W takim przypadku możesz zastosować łatkę binarną lub po prostu zastąpić istniejącą instalację OpenJDK najnowszą wersją. Alternatywnie możesz użyć komercyjnie obsługiwanego OpenJDK, takiego jak Zulu Enterprise firmy Azul.

Czy potrzebujesz każdej poprawki bezpieczeństwa?

Jeśli uważnie obserwujesz alerty zabezpieczeń, może się okazać, że nie potrzebujesz danego zestawu aktualizacji. Na przykład wydanie ze stycznia 2020 r. Wydaje się być krytyczną aktualizacją Java; Jednak dokładny odczyt pokazuje, że aktualizacja usuwa tylko dziury w zabezpieczeniach apletów Java i nie wpływa na serwery Java.

Reguła bezpieczeństwa Java nr 9: Poszukaj luk w zależnościach

Dostępnych jest wiele narzędzi do automatycznego skanowania bazy kodu i zależności w poszukiwaniu luk. Wszystko, co musisz zrobić, to ich użyć.

OWASP, Open Web Application Security Project, to organizacja zajmująca się poprawą bezpieczeństwa kodu. Lista zaufanych, wysokiej jakości narzędzi do automatycznego skanowania kodu OWASP obejmuje kilka narzędzi zorientowanych na język Java.

Regularnie sprawdzaj swoją bazę kodu, ale miej też oko na zależności innych firm. Atakujący atakują zarówno biblioteki o otwartym, jak i zamkniętym kodzie źródłowym. Uważaj na aktualizacje swoich zależności i aktualizuj system po wydaniu nowych poprawek zabezpieczeń.

Reguła bezpieczeństwa Java nr 10: Monitoruj i rejestruj aktywność użytkowników

Nawet prosty atak siłowy może zakończyć się sukcesem, jeśli nie monitorujesz aktywnie swojej aplikacji. Korzystaj z narzędzi do monitorowania i rejestrowania, aby mieć oko na stan aplikacji.

Jeśli chcesz się przekonać, dlaczego monitorowanie jest ważne, po prostu usiądź i obserwuj pakiety TCP na porcie nasłuchiwania aplikacji. Zobaczysz wszystkie rodzaje aktywności, znacznie wykraczające poza proste interakcje użytkownika. Część z tych działań będzie polegała na skanowaniu botów i złoczyńców w poszukiwaniu luk.

Powinieneś rejestrować i monitorować nieudane próby logowania i wdrażać środki zaradcze, aby zapobiec bezkarnym atakom klientów zdalnych.

Monitorowanie może ostrzegać o niewyjaśnionych skokach, a rejestrowanie może pomóc w ustaleniu, co poszło nie tak po ataku. Ekosystem Java obejmuje bogactwo komercyjnych i otwartych rozwiązań do rejestrowania i monitorowania.

Reguła bezpieczeństwa Java nr 11: Uważaj na ataki Denial of Service (DoS)

Za każdym razem, gdy przetwarzasz potencjalnie kosztowne zasoby lub podejmujesz potencjalnie kosztowne operacje, powinieneś chronić się przed niekontrolowanym wykorzystaniem zasobów.

Oracle utrzymuje listę potencjalnych wektorów tego typu problemu w dokumencie Secure Coding Guidelines for Java SE, pod nagłówkiem „Denial Of Service”.

Zasadniczo za każdym razem, gdy zamierzasz wykonać kosztowną operację, taką jak rozpakowanie skompresowanego pliku, powinieneś monitorować pod kątem eksplozji wykorzystania zasobów. Nie ufaj manifestom plików. Ufaj tylko rzeczywistemu zużyciu na dysku lub w pamięci, monitoruj je i chroń przed nadużyciami serwera na kolana.

Podobnie w przypadku niektórych procesów ważne jest, aby uważać na nieoczekiwane wieczne pętle. Jeśli pętla jest podejrzana, dodaj osłonę, która zapewni postęp pętli, i zewrzyj ją, jeśli wydaje się, że przeszedł zombie.

Reguła bezpieczeństwa Java nr 12: rozważ użycie menedżera bezpieczeństwa Java

Java ma menedżera zabezpieczeń, którego można użyć do ograniczenia zasobów, do których ma dostęp działający proces. Może izolować program pod kątem dostępu do dysku, pamięci, sieci i maszyny JVM. Zawężenie tych wymagań dla Twojej aplikacji zmniejsza ślad możliwych szkód wynikających z ataku. Taka izolacja może być również niewygodna, dlatego SecurityManagerdomyślnie nie jest włączona.

Będziesz musiał sam zdecydować, czy obejście SecurityManagersilnych opinii jest warte dodatkowej warstwy ochrony dla Twoich aplikacji. Zobacz dokumentację Oracle, aby dowiedzieć się więcej o składni i możliwościach menedżera bezpieczeństwa Java.

Reguła bezpieczeństwa Java nr 13: rozważ użycie zewnętrznej usługi uwierzytelniania w chmurze

Niektóre aplikacje muszą po prostu posiadać swoje dane użytkownika; co do reszty, dostawca usług w chmurze mógłby mieć sens.

Rozejrzyj się, a znajdziesz wielu dostawców uwierzytelniania w chmurze. Zaletą takiej usługi jest to, że to dostawca jest odpowiedzialny za zabezpieczenie poufnych danych użytkownika, a nie Ty. Z drugiej strony dodanie usługi uwierzytelniania zwiększa złożoność architektury przedsiębiorstwa. Niektóre rozwiązania, takie jak FireBase Authentication, obejmują zestawy SDK do integracji w stosie.

Wniosek

Przedstawiłem 13 zasad tworzenia bezpieczniejszych aplikacji Java. Te zasady są sprawdzone i sprawdzone, ale najważniejsza zasada brzmi: bądź podejrzliwy. Zawsze podchodź do tworzenia oprogramowania z ostrożnością i nastawieniem na bezpieczeństwo. Szukaj luk w swoim kodzie, korzystaj z interfejsów API i pakietów zabezpieczeń Java oraz używaj narzędzi innych firm do monitorowania i rejestrowania kodu pod kątem problemów z bezpieczeństwem.

Oto trzy dobre zasoby wysokiego poziomu, które pomogą Ci być na bieżąco z ciągle zmieniającym się krajobrazem bezpieczeństwa Java:

  • OWASP Top 10
  • Top 25 CWE
  • Wytyczne Oracle dotyczące bezpiecznego kodu

Ta historia „Trzynaście reguł tworzenia bezpiecznych aplikacji Java” została pierwotnie opublikowana przez JavaWorld.