sobota, 23 lutego 2008

Bezpieczeństwo skryptów z punktu widzenia programisty

Pisanie własnego kodu daje dużo satysfakcji, jednakże wiąże sie z pewnym ryzykiem, że ktoś znajdzie lukę w naszym kodzie i umiejętnie ją wykorzysta do kradzieży lub manipulacji danych, przejęcia konta, itp. Bardzo ważnym elementem przy pisaniu aplikacji jest walidacja wpisywanych/pobieranych danych. W pierwszym przypadku (wpisywanie danych) zazwyczaj oczekujemy określonego typu danych np. wartości liczbowej czy tekstu pozbawionego tagów html ( warto przemyśleć zastosowanie funkcji: string htmlspecialchars ( string $string [, int $quote_style [, string $charset [, bool $double_encode ]]] ) ), również w prosty sposób możemy sprawdzić czy wprowadzona wartość jest liczbą, przydatna możne być funkcja: bool is_numeric ( mixed $var ) oraz podobne( is_float(), is_int() ). Stosowanie takich zabezpieczeń minimalizuje ryzyko ataków typu XSS czy CSRF. Warto jeszcze dodać, że walidację formularzy powinno wykonywać sie dwukrotnie - za pierwszym razem po stronie klienta oraz za drugim razem na serwerze na wypadek gdyby podstępny użytkownik "majstrował" przy formularzu.

Kolejnym bardzo ważnym aspektem zabezpieczania skryptów jest ścieżka dostępu do pliku( zasobu). Szczególnie jest to poważny problem w przypadku tworzenia skryptu do przeglądania zawartości katalogu, należy bardzo uważać na odwołania typu: ../, ../../ itd. Oto przykład nie w pełni zabezpieczonego skryptu: Thepeak File Upload v1.3 . Można w prosty sposób wydobyć dowolny plik na serwerze( trzeba tylko oczywiście znać pełną ścieżkę dostępu do tego pliku).
Dobrym rozwiązaniem jest tutaj funkcja: string basename ( string $path [, string $suffix ] ).

W przypadku skryptów uploadujących pliki na serwer należy pamiętać o sprawdzeniu typów wgrywanych plików, dla przykładu nie powinno sie zezwalać na pliki typu: "application/x-httpd-php", "application/octet-stream" lub podobnych, ze względu na to, że mogą zostać wykonane na serwerze.

Wstrzykiwanie( injection) zainfekowanego kodu to temat bardzo rozległy i szczególnie niebezpieczny w przypadku tzw. SqlInjection. Po ataku na stronę Szkoły Hakerów, mamy nawet możliwość zrobienia tego legalnie: hackme.pdf. Ponieważ każde odwołanie sie do bazy sql wymaga napisania osobnego kodu, czasami bardzo łatwo popełnić błąd w postaci luki w systemie bezpieczeństwa, dotyczy do przede wszystkim początkujących programistów, ale jak widać na przykładzie Szkoły Hakerów, nie tylko. Szczególnie, że na stronie szkoły znalazłem również miejsce podatne na ataki XSS.

Należy również unikać wykonywania kodu podawanego w postaci jawnego tekstu(sringa), mam tu na myśli funkcję: mixed eval ( string $code_str ).

Na koniec uwaga dotycząca składowania danych: ważne dane(loginy, hasła, itp.) na serwerze powinno być przechowywane w bezpieczny sposób, w miejscach do których przeciętny użytkownik nie ma dostępu, najlepiej w postaci shaszowanej(md5, itp.).


piątek, 8 lutego 2008

Łamanie haseł - algorytmy brute force

Techniki brute force są najskuteczniejsze nie ze względu na wymyślne algorytmy, ale ze względu na prostotę działania. Schemat sprowadza się zawsze do tej samej metody którą można opisać dokładnie jednym zdaniem: "znajdź rozwiązanie sprawdzając kolejne możliwości(kombinacje)". Oczywiście algorytm można przerwać w momencie znalezienia rozwiązania, no chyba, że oczekujemy więcej poprawnych rozwiązań.

Może warto odwołać sie do jakiegoś przykładu. Niech to będzie łamanie hasła zaszyfrowanego archiwum RAR. Załóżmy, że mamy do dyspozycji program unrar (unrar.exe w środowisku za którym nie przepadam :) ) dowolny kompilator języka C( cc, gcc), bash lub dowolny język skryptowy z którego można wywoływać polecenia zewnętrzne.

Schemat działania jest prosty:

1) Definiujemy tablice znaków char tablica_znaków[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

2) Piszemy podprogram do generowania wszystkich możliwych wariacji z powtórzeniami ze znaków tablicy zadeklarowanej w punkcie (1), oczywiście wariacje muszą mieć długość od 1 do length(tablica_znaków[])

3) W pętli odpalamy unrara tj. unrar nazwa_archiwum.rar i-ta_kombinacja

Cóż, wydawać by sie mogło nic trudnego; jedyna rzecz która psuje całą zabawę to czas jaki zajmie sprawdzenie wszyskich możliwości.
Jeśli hasło ma 3 znaki( ilość możliwości = length(tablica_znaków[]) + length(tablica_znaków[]) * length(tablica_znaków[]) + length(tablica_znaków[]) * length(tablica_znaków[]) * length(tablica_znaków[]) ) czas oczekiwania na odpowiedz jest w granicach naszych oczekiwań. W przypadku dłuższego hasła potrwa to o wiele, wiele dłużej (przyrost jest wykładniczy). Nawet wspomaganie sie dzieleniem zadań na wątki niewiele sie przyda w kontekście zysku czasowego.

Można oczywiści zawęzić alfabet, jeśli wiemy, że jakiś znaków na pewno nie zawiera hasło lub stosować dodatkowe algorytmy heurystyczne( np. zakładać że między spółgłoskami musi znajdować sie samogłoska) , ale wtedy istnieje prawdopodobieństwo, że nie znajdziemy hasła.

Mimo wszystko czasami warto próbować brute-for'ca, w końcu nie wszystkich chce sie wpisywać długie i wymyślnme hasła.... a nuż sie uda.