W psychologii istnieje pojęcie piramidy (hierarchii) potrzeb. Potrzeby wyższe aktywizują się dopiero po zaspokojeniu potrzeb niższych. Również w przypadku budowania aplikacji, (w)budowania bezpieczeństwa i jego testowania są rzeczy, które mają większy priorytet niż inne. Dopiero po ich realizacji można przejść "poziom wyżej".
Piramida potrzeb
Aplikacja MUSI działać
Pierwszą podstawową potrzebą jest to, by aplikacja działała i realizowała swoje cele. Jak już kilka razy pisałem aplikacje zwykle mają jakiś cel. Istnieje jakaś potrzeba, podejmowana jest więc decyzja o wdrożeniu lub stworzeniu aplikacji, która potrzebę (potrzeby) będzie zaspokajać/realizować. Sam proces definiowania wymagań odnośnie aplikacji, modyfikowania ich w trakcie jej tworzenia/wdrożenia i konfrontacja koncepcji z projektem a projektu z rzeczywistością może być... zaskakująca, co zresztą doskonale pokazuje znany(?) obrazek:
Osiągnięcie stanu, w którym aplikacja działa i realizuje swoje pierwotnie zdefiniowane zadania (a przynajmniej pewien "wystarczający" ich podzbiór) ma znaczenie priorytetowe. To zadanie otrzymuje większość dostępnych zasobów i zagładza (od zagłodzenia procesu) pozostałe zadania, które tak krytyczne nie są, a przynajmniej nie wydają się być.
Czym to objawia się w praktyce? Ciekawym zajęciem może być obserwacja zmian zachodzących w harmonogramach projektów. Można często zaobserwować wydłużanie się etapu tworzenia kodu i jednocześnie skracanie czasu poświęcanego na testy (weryfikację poprawności działania) stworzonego i wdrożonego systemu. Skracanie, ponieważ data produkcyjnego uruchomienia systemu jest "święta" i nie może zostać w żaden sposób przesunięta.
Poza skróceniem czasu przeznaczonego na testy, skraca się również czas zarezerwowany na poprawę znalezionych błędów. W wielu przypadkach przyjmowane jest optymistyczne założenie, że takich błędów nie będzie. W efekcie tego założenia zakończenie testów zbiega się z udostępnieniem produkcyjnym systemu i czasu na wprowadzenie poprawek po prostu nie ma.
Choć skrócenie czasu przeznaczonego na testy, poprawki i ich weryfikację jest zjawiskiem niekorzystnym, to zdecydowanie gorsze efekty ma to, co dzieje się po stronie "produkcji". Działanie pod presją czasu często prowadzi do tego, że tworzony kod jest niskiej jakości (w szczególności - nie jest bezpieczny). Powód jest prosty - dążenie do osiągnięcia sytuacji, w której spełnione są wymagania funkcjonalne. Wszystko to, co nie jest niezbędne, odkładane jest "na potem". Rezygnuje się z niektórych dobrych praktyk, tylko po to, by zdążyć na czas. I później w kodzie można znaleźć takie fragmenty:
$stm = $db->prepare('SELECT * FROM tabela WHERE a=:p_a AND b=:p_b AND c='.$c); $stm->bindParam(':p_a', $a, PDO::PARAM_INT); $stm->bindParam(':p_b', $b, PDO::PARAM_STR, 32);
...i jak łatwo się domyślić w $c zapewne będzie SQLi... Dodatkowym rezultatem tego typu praktyk będą prawdopodobnie duże niespójności w aplikacji, przez co wyciąganie ogólnych wniosków będzie niemożliwe, co z kolei spowolni proces testów.
A jak to wygląda po stronie testów?
Jak to przekłada się na testowanie bezpieczeństwa? Tu też widzę pewną hierarchię potrzeb (i zadań)... Pewne warunki muszą być spełnione po to, by można było nie tylko rozpocząć testy, ale by również testy były efektywne. Testy, które zostaną przeprowadzone, również układają się w pewne logiczne następstwo. Najpierw rzeczy podstawowe, w dużym stopniu uniwersalne. Dopiero później rzeczy specyficzne dla konkretnej aplikacji.
Aplikacja musi działać (a przynajmniej badana funkcja)
Po pierwsze trzeba sprawdzić, czy aplikacja działa. Trudno testować jest funkcję, która nie jest jeszcze zaimplementowana lub działa w sposób błędny. Sensowność testowania funkcji, która ulegnie istotnym zmianom (bo nie przeszła testów funkcjonalnych czy akceptacyjnych) jest wątpliwa. Owszem, wykazanie błędów bezpieczeństwa jest przydatne, bo w trakcie modyfikacji można je jednocześnie usunąć, to stwierdzenie, że błędów nie ma jest praktycznie bezwartościowe - błędy mogą zostać wprowadzone w trakcie koniecznych modyfikacji.
Sprawdzenie czy aplikacja działa nie oznacza oczywiście przeprowadzenie przed testami bezpieczeństwa testów funkcjonalnych. Chodzi tu o zweryfikowanie czy dana funkcja była już testowana i czy jest "przyjęta". Jeśli tak - można ją testować. Co w przypadku, gdy dana funkcja jest niegotowa? Można wykonać szybki rekonesans po to, by wychwycić "grube" błędy. Trzeba jednak pamiętać, że do tego fragmentu aplikacji trzeba będzie wrócić, gdy będzie gotowy.
I jeszcze jedno. Do listy sposobów jak wkurzyć pentestera dodałbym trzy, dość istotne punkty:
- Niech aplikacja działa niestabilnie. Wykonanie dwa razy tej samej operacji pod rząd daje różne rezultaty. I niech pojawiają się losowo błędy 500. Nie zapomnij o nieregularnych i absolutnie niezapowiedzianych aktualizacjach aplikacji, oczywiście bez żadnego logu zmian.
- Niech aplikacja działa wolno. Przecież to tylko dwie minuty czekania na odpowiedź serwera. I nie, nie da się tego poprawić, bo akurat teraz są wykonywane również testy wydajnościowe.
- Połącz dwa powyższe punkty w jedno. Niech pentester poczeka sobie dwie minuty na odpowiedź serwera tylko po to, by dowiedzieć się, że wystąpił błąd. Tym razem. Bo przy drugiej próbie niech wszystko działa poprawnie. I nie zapomnij umilić czasu oczekiwania jakąś hipnotyzującą animacją!
Zbyt długi czas, w którym aplikacja zgłoszona do testów "nie działa" (lub działa tak, jakby nie mogła) jest o tyle niebezpieczny, że tego straconego czasu zwykle nie można odzyskać. Można z dużym prawdopodobieństwem zakładać, że priorytetem będzie utrzymanie wcześniej podanego terminu produkcyjnego udostępnienia systemu. Jeśli z przewidzianych 20 dni roboczych zniknie nagle 5 (lub więcej), zaczyna brakować czasu. I nie, nie uda się go odzyskać "pracując dłużej", bo testerzy to też (tylko) ludzie i mają swoje granice wytrzymałości. A testy bezpieczeństwa to (często) monotonna, metodyczna praca wymagająca skupienia.
Sprawdzenie podstawowych rzeczy
Jeśli aplikacja działa, w drugiej kolejności warto poszukać błędów w architekturze (przykład: Znajdź błąd projektowy: wykorzystanie AJAX (część I)) oraz typowych błędów w implementacji.
Ten etap niestety wciąż zajmuje za dużo czasu. I, również niestety, często jest bardzo owocny. Co zrobić, gdy okaże się, że aplikacja została zaprojektowana błędnie a błąd jest tak poważny, że w zasadzie należy aplikację napisać od nowa? Co zrobić, gdy okaże się, że typowe błędy w implementacji popełniane są nagminnie i potrzebna jest bardzo duża ilość poprawek? Przypominam, że czas przeznaczony na testy został skrócony do minimum i nie został przewidziany czas na poprawki...
Współczuję kierownikom projektów, którzy znajdują się w sytuacji opisanej wyżej. Jakie możliwości działania mają? Obawiam się, że nie mają wielkiego pola manewru... Osobiście uważam, że prawdopodobieństwo wystąpienia takich sytuacji trzeba minimalizować poprzez zmianę cyklu procesu tworzenia oprogramowania (jeśli oprogramowanie wytwarzane jest "własnymi siłami") lub wymaganie odpowiedniego procesu tworzenia oprogramowania u dostawców.
I coś więcej niż podstawy...
Trzecim aspektem, któremu obecnie niestety nie poświęca się wystarczająco dużo uwagi jest poszukiwanie błędów w logice biznesowej aplikacji oraz to, o czym pisał ostatnio Przemek, czyli testy wynikające ze scenariuszy ataków.
Niestety, z tym czymś więcej pojawia się pewien problem. A nawet kilka problemów. Warto zadać sobie pytanie, czy i w jakim zakresie można przystąpić do badania tego czegoś więcej, jeśli aplikacja nie została zbadana (dokładnie) pod kątem podstawowych problemów. Albo inaczej - czy można pominąć testy podstawowe i przejść bezpośrednio do badania logiki biznesowej oraz sprawdzenia możliwości określonych (wcześniej, na przykład tak: Don't Forget EVIL User Stories) celów intruza? Jak zwykle odpowiedź będzie zależała od konkretnego przypadku. Testowania pewnych rzeczy mam już dość, ale obawiam się, że do czasu, gdy te podstawowe rzeczy będą uwzględniane w procesie tworzenia aplikacji, wciąż to coś więcej będzie odkładane na później, bo te podstawowe rzeczy zajmują zbyt wiele zasobów. Tak jak w piramidzie potrzeb...
No dobrze, nie jest aż tak źle. W rzeczywistości w trakcie testów przychodzi również czas na to coś więcej, ale prawdą jest to, że kwestie związane z podstawowymi zagadnieniami zajmują zbyt dużo czasu. Nie można przejść dalej, bo wciąż ilość podstawowych błędów jest duża. Jest lepiej niż kiedyś, ale ciągle w procesie tworzenia aplikacji czegoś brak.
O rany, też was wkurzały te pie..ękne generatory wniosków unijnych?
A wspomniane przez Ciebie wnioski unijne nie są odosobnionym przypadkiem wolno działającej aplikacji