Aby ułatwić tworzenie bezpiecznych modułów PHP, zebrałem swoisty „dekalog projektanta”. Języki programowania nie są ze swojej natury niebezpieczne. To projektanci konkretnych systemów popełniają błędy narażające użytkowników i szkodzące wizerunkowi sieci
W zestawieniu celowo pomijam problem niebezpieczeństwa podsłuchania komunikacji naszego serwera z komputerem użytkownika. Nie jest to bowiem kwestia PHP i rozwiązaniem jest użycie szyfrowanego protokołu SSL/HTTPS.
Wszystkie dane, nie tylko przesyłane przez formularze, można łatwo sfałszować.
Standard HTTP zakłada, że przeglądarka WWW użytkownika sama i niesprawdzana tworzy pełne zapytanie do twojego serwera. Może w nim podać cokolwiek. Np. że nazywa się NinjaExplorer 3.14 i działa na systemie ZX Spectrum, a w ogóle to numer IP komputera należy do papieża.
Parametry ukryte formularzy są tak samo widoczne i zmienialne, jak te jawnie wpisywane przez użytkownika, nie zakładaj więc, że wartości, które wpiszesz do formularza, dostaniesz z powrotem.
Dotyczy to zwłaszcza informacji przesyłanych do bazy danych, ale też np. tekstów przetwarzanych przez wyrażenia regularne. Przydatna skądinąd funkcja pregreplace_ może być zmanipulowana do uruchamiania skryptów.
Podobnie znak nowej linii w nazwie nadawcy może zamienić funkcję mail w maszynkę do wysyłania spamu za pomocą Twojego serwera. Dzieje się tak dlatego, że \n jest znakiem specjalnym w formacie nagłówka e-maila i można po nim umieścić dodatkowe instrukcje.
Zaprzyjaźnij się z~funkcjami typu ctypealnum, mysqlrealescapestring, intval czy htmlentities.
Zawsze im mniej, tym bezpieczniej. Np. czy użytkownik musi mieć możliwość wstawiania kodu HTML do swojego podpisu na forum? Z takimi uprawnieniami, wstawiając kod javascript, mógłby np. wykradać konta innym użytkownikom. W tym konkretnym przypadku alternatywą jest zastosowanie czegoś w rodzaju BBCode.
Potwierdzaj powtórnie czystość danych przed ważnymi operacjami. Np. pliki inkludowane powinny zakładać, że mogą być uruchamiane podstępnie poza systemem, powinny więc same sprawdzać np. uprawnienia użytkownika do czynności, którą wykonują.
Nie bój się prosić użytkownika o powtórzenie hasła przed ważnymi operacjami. Zmieniaj wtedy też identyfikator sesji funkcją sessionregenerateid.
Żeby ułatwić użytkownikowi życie, proś go w takiej sytuacji tylko o wpisanie hasła, a nie o pełne powtórne zalogowanie.
Ciasteczka (cookies) przeglądarki użytkownika można podejrzeć lub ukraść. Przechowywanie tam haseł to proszenie się o kłopoty. Używaj danych sesji lub wpisów do bazy danych – informacji przechowywanych na twoim serwerze.
Metoda ta nie daje bezpieczniejszych wartości danych, ale znacznie utrudnia phishing i inne ataki polegające na podszywaniu się albo podkładaniu zmanipulowanych linków.
Czytając wartości pól formularza, używaj tabeli $POST a nie $REQUEST.
Metoda GET powinna być używana tylko wtedy, gdy użytkownik pyta o informację i to pytanie może bezpiecznie powtarzać, np. przy wyszukiwaniu. Efektywnie ustawienie formularza z metodą GET jest tym samym co umieszczenie na stałe linku na stronie.
Ponieważ nazwy metod GET i POST nie zostały wybrane przypadkowo, większość przeglądarek inaczej je obsługuje i np. pyta o dodatkowe potwierdzenie przed powtórnym wysłaniem formularza POST.
Jeżeli chcesz dodatkowo zapewnić unikalność operacji POST, umieść w nim dynamicznie unikalny „token” przechowywany równolegle w sesji lub bazie danych. Zazwyczaj takie zabezpieczenie utrudnia użytkownikowi edycję danych w serwisie WWW (np. ustawień jego konta), więc powinno być ograniczone do rzeczywiście unikalnych operacji.
Metodą „brutalnej siły”, testując tysiące albo miliony haseł, można w końcu odgadnąć to właściwe. Łatwo można sprawić, by takie podejście było niepraktyczne, jeżeli wymusi się choćby 15-sekundową przerwę między kolejnymi próbami zalogowania się na jedno konto użytkownika.
Pliki z hasłami do bazy danych i innymi ważnymi danymi można umieścić w katalogu niedostępnym przez HTTP. Np. zamiast w /home/me/www/include/ w /home/me/secrets/
Pomijając podsłuchiwanie komunikacji, przechwycenie numeru sesji jest możliwe albo przez wykorzystanie luk w przeglądarce wykorzystywanej przez użytkownika, albo przez wprowadzenie na twoją stronę kodu, który przez javascript prześle odpowiednie dane na serwer napastnika.
Jeżeli dobrze czyścisz wszystkie wyświetlane dane, ryzyko jest niewielkie. Możesz je jednak dodatkowo ograniczyć używając dodatkowych parametrów do weryfikacji sesji poza samym jej identyfikatorem.
Taki dodatkowy „token” najlepiej przekazywać przez parametry zaszyte w URL, dzięki czemu napastnik musiałby przechwycić jednocześnie identyfikator sesji ofiary jak i jego komunikację z naszym serwisem, aby przejąć sesję.
Możesz w ten sposób zwiększyć też bezpieczeństwo formularzy przez przekazywanie tokena o krótkim czasie życia przez pole ukryte oraz przez zmienne sesji. W ten sposób będziemy mieli pewność, że użytkownik odsyła nam formularz, który przed chwilą mu wysłaliśmy.