W ramach eksternistycznego zaliczenia kursu PHP na studiach, prowadzący zaoferował mi przygotowanie krótkiej prezentacji o języku. Prezentacje nie są tym, co programiści lubią najbardziej. Zamiast prezentacji wyszedł krótki tekst, a zamiast możliwości języka są błędy ludzi.
Całość zamieszczam i tutaj, może się komuś na coś przyda. O ile wierzę w swoją wiedzę, to zastrzegam z góry, że praca nie była jeszcze oceniana. Przepraszam też za wielkość, ale to AbiWord taki duży plik wygenerował :)
Pobierz PHP i aplikacje WWW (290 kB, PDF)

ufff… na szczęście, z Twojej prezentacji nie dowiedziałem się niczego, czego bym wcześniej nie wiedział :-)
Choć przyznaje, że przy ostatnim punkcie (’upload’), zrobiłem szybki rachunek sumienia, czy gdzieś ostatnimi czasy nie popełniłem tego błędu :-)
Chyba najlepszym/najłatwieszym sposobem zabezpieczenia się przed bugami o których piszesz, to stosowanie framework’ów (np.: w zden framework metoda _redirect() robi header() + exit(); spróbujcie tylko napisać UnitTesty które to testują :-))).
Albo przynajmniej korzystanie z gotowców (klas/metod) mąrzejszych od nas, którzy już przez te problemy się przegryźli.
Podoba mi się ten dokumencik. Taka wiedza w pigułce. Niektórym bardzo się przyda. Zresztą połowa z tych błędów nie dotyczy tylko i wyłącznie PHP.
Co do SQL injection - wielu ludzi naiwnie bazuje na magic_quotes, zapominając, że czasami przekazujemy wartości typu int. Bardzo ładnie to pokazałeś w tym dokumencie
Z ciekawostek - warto pamiętać, żeby w configu wyłączyć opcję expose_php. Dlaczego?
Dlatego: http://carstein.kill-9.pl/~mike/check_version.py
(kod naklepany w 5 minut). A po co ktoś ma wiedzieć, jakiej wersji PHP używacie? To samo zresztą dotyczy server_token w configu apache.
A ja bym się przyczepił, że „inicjalizowania zmiennych”, a nie „inicjowania”. Inicjowanie to z rozpoczynaniem jakiegoś procesu raczej chyba…
Dzięki za ten pdf. Na szczęście niczego nowego się nie dowiedziałem, ale to bardzo pożyteczny test.
Tak w kwestii dołączania plików .inc, to owszem, można je zastąpić plikami .php, ale można spokojnie używac .inc, dodając odpowiednią dyrektywę do pliku konfiguracyjnego Apache’a lub do pliku .htaccess. Wyglądałoby to mniej-więcej tak:
Order Deny,Allow
Deny from All
Oczywiście, jeśli nie mamy możliwości zmiany treści apache.conf lub mamy zabronione używanie .htaccess, to wtedy Twoja metoda jest jak najbardziej ok. W sumie zawsze jest ok, ale sygnalizuje tylko, że jest też inny sposób.
Co do dołączania zewnętrznych plików (Ślepe dołączanie kodu) to metodą radzenia sobie z tym jest umieszczenia w kodzie funkcji sprawdzających, co wogóle jest nam dawane z zewnątrz.
W przypadku obrony przed SQL Injection, również warto zaopatrzeć się w sprawdzacze tego, co jest wprowadzane przez formularze.
Brakuje mi troche wzmianki o directory traversal, bo jestem ciekaw Twoich propozycji obrony przed takimi atakmi. Ogólnie bardzo ciekawa prezentacja (artykuł?):) Pisałem coś podobnego parę dni temu ale bardziej szerzej (temat: Bezpieczeństwo WWW, forma: konspekt ćwiczeń dla studentów na przedmiot Bezpieczeństwo i Ochrona Danych w Systemach Komputerowych).
Przepraszam za bałagan, ale oczywiście w ostatnim zdaniu chodziło mi o “pisanie nie tylko o php”. Pierwsza forma dziwnie wygląda;p
Jejku, sen daje o sobie znać, ale i tak wybacz mi bardzo, zapomniałem o < i > przy dyrektywie… powinna ona wyglądać tak:
<FilesMatch “\.(inc)$”>
Order Deny,Allow
Deny from All
</FilesMatch>
rozbit:
Od walidacji formularzy jest logika kontrolera, od przekazywania danych do bazy logika modelu. Model powinien zadbać o to, żeby nie zepsuć bazy nawet jeśli kontroler jest wadliwy i stąd preparowane zapytania albo procedury składowane (oba dają dodatkowy zysk wydajności).
Jeśli kod aplikacji jest bezpieczny, to chętnie pokażę ci całą strukturę katalogów serwera i nadal będę mógł spać spokojnie :)
PS: to powyższe dotyczy ataków typu Directory Traversal - najprostsza metoda to trzymanie plików w postaci <suma-kontrolna-md5>.<rozszerzenie-na-podstawie-typu-mime>. Faktyczną nazwę trzeba znać tylko w momencie serwowania plików binarnych, przeznaczonych do zapisu na dysku, a wtedy można ją wygenerować na podstawie opisu pliku w bazie.
bardzo interesujące, dzię-ku-je-my!
(chociaż dyskusyjne jest używanie tabl. $_REQUEST :)
adam:
W przypadku metod rutujących wykonanie kodu pomiędzy modułami, część parametrów czasem przyjdzie przez POST, a czasem przez GET - wygodniej użyć _REQUEST wtedy. Nie mówię o zastępowaniu nim jakichkolwiek odwołań.
fajny art., dzięki
Uffff :) też się cieszę że błędy wymienione przez Patrysa mnie nie dotyczą (ale za to tępię je u innych :>).
Co do pracki - bardzo dobra, skupiasz się na najczęstszych błędach :)
Daję 4 :>
Pozdr
Praca jest jak najbardziej wporządku. Chociaż dodał bym jakieś obrazki i może strony, na których jest napisane szerzej o bezpieczeństwie.
Export z AbiWorda ssie. Same kwadraciki widze.
Znaczy, że nie masz dobrych czcionek w systemie.
Uwaga na temat .htaccess jest calkiem na miejscu. Samo istnienie konfiguracji w pliku .php moze nie wystarczyc. Poza tym strzezonego Pan Bog strzeze ;]
Przerzuc sie poza tym na latexa ;] Znacznie milej to wyglada :)
Art dobry, choc uwazam, ze za ostry w slowach. Ludzie, ktorzy popelniali takie bledy do momentu przeczytania arta moga poczuc sie urazeni. Zamiast “wyzywac” mozna by ujac to delikatniej w slowach.
Ale to juz jest licentia poetica :)
Pozdrawiam
Jak już wspomniało parę osób powyżej. Nowych rzeczy dla mnie.. brak.
Jednak z punktu widzenia osoby dopiero stawiającej kroki w programowaniu w PHP, bardzo przydatny.
carstein: od tego jest PDF, żeby czcionki niestandardowe załączyć. Ale kto teraz potrafi wygenerować dobrego PDFa. (prócz pdflateksa ;)
Patrys:
ślepe dołączanie kodu -> należało by wspomnieć o apparmor, który w opisanym przypadku byłby dodatkowym zabezpieczeniem.
cookie injection -> jeśli już mówimy o nieinwazyjności w sesję PHP trzeba by tu wspomnieć, że dobrze jest zdefiniować samodzielnie session_save_path(’/some/path/’);
inny pomysł - może niezbyt świeży - to próba zabezpieczenia aplikacji przed wstrzyknięciem obcego kodu używając mod_rewrite, jeśli aplikacja z założenia nie ma używać _żadnych_ zewnętrznych URL przekazywanych via $_GET.
Pisząc o bezpieczeństwie aplikacji www nie wspomniałeś o umiejętnościach, jakie powinien posiadać administrator danego serwera www oraz (bardzo często) o konieczności współpracy programisty i admina (a’propos mojego wcześniejszego nawiązania do apparmor).
Podsumowując - w bardzo udany sposób przedstawiłeś tu problematykę bezpieczeństwa aplikacji web, brawo !
Przyjemne antybugowe repetytorium.
mcv: A ja bym się przyczepił, że „inicjalizowania zmiennych”, a nie „inicjowania”. Inicjowanie to z rozpoczynaniem jakiegoś procesu raczej chyba…
Pozwole sobie zacytowac, bo jest to czesto popelniany blad (Patrys go nie popelnil):
Tłumacze tekstów informatycznych z godną podziwu konsekwencją angielski termin initialization tłumaczą jako inicjalizacja zamiast np. inicjowanie (chyba lepiej) lub inicjacja. Będę wdzięczna za opinię na ten temat.
Anna Mazik
W słowniku języka polskiego (dostępnym na naszych stronach WWW) nie ma słowa inicjalizacja. Jest natomiast inicjacja oraz inicjowanie. Inne słowniki też nie notują inicjalizacji. W tekstach informatycznych jeśli coś jest inicjowane przez coś innego (np. gdy obiekt po utworzeniu wymaga jeszcze dodatkowego zainicjowania go do działania) użyłbym słowa inicjowanie, natomiast gdy coś inicjuje się samo (np. podczas utworzenia wykonuje automatycznie wszelkie procedury niezbędne do działania) mówiłbym o inicjacji.
— Adam Zaparciński, PWN
co do plików .inc, to najlepiej jest trzymać wszystko poza Document Root, po co te pliki mają być wogóle osiągalne od strony klienta? (trochę tak jak pliki wykonywalne są w /bin, a nie ma tam przecież bibliotek, prawda?)
co do configuracji, to czy mądre/sensowne jest trzymanie configa w zmiennej $_SERVER['my_config'] ? Czy to jest bezpieczne? Czytałem kiedyś o tym, i się zastanawiam.
Pozdrawiam
Łukasz Jarochowski
ljarochowski: nie zgadzam się z trzymaniem .inc poza zasięgiem klienta - przy poprawkach admin będzie zamęczany w przypadku poprawek/zmian/innych genialnych pomysłów klienta.
Powyższe proszę traktować jako poparcie pomyslu Patrysa: pliki PHP trzymaj z rozszerzeniem .php.
wojtosz: oczywiście że pliki powinny mieć rozszerzenie .php, ale myślę że warto tak zaprojektować aplikację, żeby dawała możliwość umieszczenia logiki poza “sceną”, żeby klient nie musiał mieć dostępu do plików poza Document Root, można w tym celu użyć np. set_include_path(’nasz-katalog-poza-doc-root’), albo to i do tego jeszcze __autoload, żeby nie mieć require’ów rozsianych po wszystkich plikach.
Nie wiem czemu admin - (kto to jest admin, administrator aplikacji, serwera, zespół programistów?) - miałby mieć z taką konfiguracją jakiekolwiek problemy. Poza tym - po co trzymać szablony w zasięgu klienta?
Co do include w “Ślepe dołączanie kodu” to myślę że ominięciem problemu jest po prostu stworzenie ponumerowanej listy plików np. dla “?id=1″ odpowiada jakiś plik, dla “?id=2″ jakiś inny, a dla “?id=33″, “?id=bujakasza.html” czy “?id=www.google.pl” dostaniesz else czyli błąd 403. :) Mylę się?
ljarochowski:
admin -> administrator serwera.
Po pierwsze, na początku nie napisałeś, że chodzi o aplikację opartą o szablony - ustosunkowałem się to tego co było napisane (nie wiem jaki był Twój zamysł, przesłanie).
Po wtóre - nie napisałem, że admin będzie miał problemy, tylko że będzie zamęczany w przypadku poprawek, co należy rozumieć: admin kocha swój spokój i nie lubi marnować cennego czasu na podmianę zawartości plików konfiguracyjnych, bo takie jest życzenie usera o 2 w nocy.
Na zakończenie prośba: pisz treściwie i dopełniaj treść wyrażanych opinii, a nie będzie potrzeby stosowania sprostowań :)
Bardzo fajny art z pewnościa przyda się osoba rozpoczynajacym swoja przygode z php i chcacym pisać bezpiecznie.
Brakuje mi tu tylko paru słów na temat przechowywania haseł w db. Może coś o soli jak w systemach unix’owych?
Swoja droga słyszałem, że lepiej od mime_content_type jest używać $_FILE. Nagłówek zawsze moża spreparować a dalej wstawić treść wykonywalną.
empathon:
Co masz na myśli, mówiąc o $_FILE?
I co da spreparowanie nagłówka PNG, skoro plik binarny zostanie zapisany właśnie jako .png w związku z tym (bez różnicy, jakie miał oryginalnie rozszerzenie)?
Mistejk, wyglada na to że mime_content_type zwraca to samo co $_FILE. Tak to jest jak coś pisze po kilkunastu godzinach siedzenia nad ksiażkami (eh sesja).
Sorry za zamieszanie. Pozdrawiam
“Wstęp
Niniejszy tekst powstał jako forma ostrzeżenia przed błędami, które popełniają nawet zawodowi programiści.”
Mam do Ciebie duzo szacunku i nie chce pisac co mysle w tej chwili o Tobie po przeczytaniu tego PDF’a, dlatego tylko chce prosic o zmiane powyzszego zdania. Najlepiej bedzie jesli usuniesz fragment od przecinka do kropki.
Jesli “zawodowi programisci” popelniaja takie bledy, to lepiej zeby trole przejely Internet.
…:
Tak, takie błędy popełniają zawodowi programiści. Zawodowi, jako “pracujący od lat w zawodzie,” a nie jako “specjaliści.”
I widziałem je w naprawdę dużych firmach, gdzie spodziewałbym się, że przy dziesięciu chętnych na miejsce jest spory odsiew. Widziałem takie kwiatki w wykonaniu ludzi, którzy pracowali wcześniej dla dużych portali (to wyjaśnia, czemu wiele portali tak szybko padło) :]
Dobrze, ze ktos o tym wszystkim napisal. Przyznac bowiem musze, ze zaczynajac przygode z PHP popelnialem wiekszosc z tych bledow. Nie zdawalbym sobie z tego sprawy, gdyby kilka bardziej zaawansowanych osob mnie nie uswiadomilo. Byc moze ten artykul rowniez kogos uswiadomi.
Najbardziej ubawilem sie widzac te linie:
zrobCosStrasznego();
:]
Faktycznie całkiem niezła esencja bezpieczeństwa.
Brakuje mi w zasadzie dwóch (choć pewnie o czymś sobie teraz nie przypominam) rzeczy:
1. Właściwie, to nie potrafię zrozumieć, czemu nikt o tym nie wspomniał, bo to zdecydowanie najczęściej popełniany błąd:
HTML Injection
Zbyt dużo chyba mówić nie muszę, połowa amatorskich for, systemów komentarzy, itp. posiada taką dziurę, choć to chyba akurat pierwsza dziurą, którą młody programista się uczy omijać.
Jednak nie należy jej z tego powodu lekceważyć: nieraz ludzie nieco bardziej zaawansowani, nie wiem, czy z rutyny, czy czegoś innego, pamiętają o zabezpieczenia “głównych” miejsc, jak treści postów, itp., a nie zabezpieczają tych “bzdurek”.
Pamiętam, że swego czasu Spinacz escape’ował kod HTML w treściach postów, natomiast w ich tytułach, nazwach zdjęć, itp. już nie. A Chojnaca za amatora bynajmnmiej nie uważam.
Podobnie zdarza się nieraz proste kopiowanie (lub z modyfikacją) czegoś z GET na wyjście aplikacji - i wtedy znów odpowiednio spreparowany link i jest problem.
2. Bardzo ważne ze względu na to, że jest to dość wyjątkowa dziura: niewiele ludzi o niej wie, nie sprawia wrażenia groźnej, a jednak.
Chodzi mianowicie o to, aby nie zezwalać na requesty POST z obcym refererem (lub nawet i z pustyym - zależnie od tego, jak restrykcyjni chcemy być).
Wydaje się naprawdę śmieszną bzdurką, prawda?
Ale jeśli w jakimś serwisie podam linka na zewnętrzny serwer, gdzie umieszczę formularz z odpowiednio wypełnionymi danymi i go autosubmituję poprzez JS, to wyjdzie na to, że każdy, kto tu wejdzie zmieni sobie np. dane profilu osobowego.
Jeśli jeszcze lepiej pokombinuję i zrobię jakąś prowizoryczną stronę z jakimiś treściami z dupy, aby tylko przytrzymać na niej trochę kolesia, a w ukrytej ramce zacznę wysyłać całą serię takich formularzy praktycznie bez wiedzy wchodzącego, to mogę nawet wywołać małą reakcję łańcuchową. Bo jeśli załóżmy przykładowe Grono by nie było zabezpieczone na tego referera, przygotowałbym tak tego mojego “wirusa”, że każdy wchodzący zaczyna na Gronie wysyłać posty do przypadkowych tematów z linkiem do tej mojej strony, to wszystko by już poszło lawinowo - domyślam się, że po dobie od zamieszczenia przeze mnie pierwszy raz linka linków tych by już było na całym gronie i parędziesiąt tysięcy.
Warte przemyślenia.
PHP i aplikacje WWW - ciekawie napisana praca.Gratuluję.
Często tu zaglądam. Piszecie ciekawe arty.