Audyt bezpieczeństwa aplikacji PHP: co sprawdzamy, zanim będzie za późno
Autor:
Paweł Matusiak
·
Większość wycieków w małych i średnich firmach dotyczy starych paneli PHP, o których wszyscy wiedzą, że działa. Audyt nie jest oskarżeniem programisty — to lista ryzyk, które da się zamknąć, zanim ktoś je wykorzysta.
Typowy scenariusz: firma ma panel od 2016 roku. Logują się handlowcy, księgowość i czasem stażysta. Hasło administratora jest w mailu. PHP na serwerze ma kilka wersji wstecze. Nikt nie wie, czy są kopie z ostatniego tygodnia. To nie jest zaniedbanie złośliwe — to zwykły dług techniczny. Dopóki nikt nie wejdzie, wszystko działa. Audyt w GESOFT nie jest oskarżeniem ówczesnego wykonawcy. Jest listą, którą da się zamknąć w kolejności: dziś, w tym kwartale, albo przy przepisaniu fragmentu.
Nie sprzedajemy testów penetracyjnych z czerwonym raportem na 80 stron i bez priorytetów. Sprzedajemy przegląd, który prezes i administrator zrozumieją: co jest otwartymi drzwiami, co jest złym nawykiem, a co poczeka. Mapujemy to na OWASP Top 10 2025 i na to, czy da się łatwo załatać, czy taniej postawić nowy backend na Laravelu i przenieść dane. Podpisujemy NDA. Kod zostaje u Ciebie.
Co obejmuje audyt w GESOFT
1. Aplikacja
- Logowanie: brute-force, reset hasła, sesje, czy da się ominąć uprawnienia znając URL (IDOR / złamana kontrola dostępu — A01).
- Formularze i API: SQL injection, XSS, CSRF, upload plików (czy da się wgrać skrypt zamiast PDF-a).
- Tajemnice w kodzie: hasła do bazy, klucze API, dump-y SQL w publicznym katalogu, .env w Git albo pod /.env.
- Uprawnienia ról: czy handlowiec widzi dane, których nie powinien; czy ukryty przycisk to jedyne zabezpieczenie.
- Logi: czy da się odtworzyć, kto usunął rekord, i czy w logach nie ma haseł oraz PESEL.
- Obsługa błędów: czy produkcja wylewa stack trace (A10), czy timeout płatności księguje podwójnie.
2. Zależności i łańcuch dostaw
Sprawdzamy wersję PHP, Laravela (albo innego frameworka) i paczek Composer/npm pod kątem znanych CVE. Stary Laravel 5.x albo PHP 7.2 to dziś otwarte drzwi — nawet jeśli kod biznesowy jest w porządku. To A03 z listy 2025: awarie łańcucha dostaw. Lockfile, porzucone paczki, skrypty zostawione w public/, zapomniany phpMyAdmin — częstsze niż filmowy haker. composer audit i przegląd composer.json nie zastępują review, ale w godzinę pokazują, czy stoicie na bibliotece z RCE z zeszłego kwartału.
3. Serwer i wdrożenie
- Czy katalog .env i Git nie są publiczne, czy backup SQL nie leży pod /backup.sql.
- Czy działa HTTPS i czy da się wejść przez HTTP i wysłać hasło otwartym tekstem.
- Uprawnienia plików, dostęp SSH (hasło kontra klucz), firewall, osobny użytkownik bazy z minimalnymi prawami.
- Kopie zapasowe: czy istnieją, czy są poza serwerem, czy ktoś próbował je odtworzyć — backup bez testu to nie backup.
- Debug i narzędzia deweloperskie na produkcji, listowanie katalogów, domyślne hasła paneli hostingu.
Jak wygląda współpraca krok po kroku
- Rozmowa i NDA. Mówisz, co panel robi, kto się loguje, czy był już incydent.
- Dostęp do kodu (Git albo archiwum) i — do części serwerowej — konto z ograniczonymi uprawnieniami albo rozmowa z administratorem. Nie potrzebujemy haseł produkcyjnych do bazy na maila.
- Przegląd statyczny i checklista OWASP: auth, injection, konfiguracja, zależności, logi, wyjątki.
- Raport z priorytetami i widełkami naprawy. Osobno: łatka, plan kwartalny, rekomendacja rewrite fragmentu.
- Jeśli chcesz — wdrażamy poprawki albo nowy system etapami. Git i 6 miesięcy gwarancji przy pracach naprawczych / nowym kodzie.
Nie piszemy exploitów ani proof-of-concept na Twoją produkcję. Nie atakujemy systemu, żeby się pochwalić zrzutem. Tam, gdzie trzeba potwierdzić podatność, robimy to kontrolowanie, na kopii albo na teście, i opisujemy ścieżkę słowami, które wystarczą do naprawy. Celem jest zamknięcie drzwi, nie teatr.
Naprawiać czy pisać od nowa?
Nie każda stara aplikacja zasługuje na rewrite. Jeśli logika biznesowa jest jasna, a dziury da się załatać (aktualizacja PHP, Laravel, logowanie, nagłówki, kopie) — łatamy. Przepisujemy, gdy:
- Framework jest porzucony albo kod to PHP w jednym pliku bez testów i bez dokumentacji.
- Nikt nie jest w stanie bezpiecznie dodać nowej funkcji — każda zmiana to rosyjska ruletka na produkcji.
- Wymagania RODO (role, usuwanie danych, zgody) wymagają przebudowy modelu danych, nie jednej kolumny.
- Koszt kolejnych łatek zbliża się do kosztu nowej, utrzymywalnej wersji — i to widać po dwóch sprintach, nie po slajdzie.
Nowy system stawiamy na Laravelu i przenosimy dane. Stary panel może działać równolegle przez okres przejściowy. Logowanie i 2FA projektujemy od razu porządnie — patrz uwierzytelnianie w Laravelu — zamiast przenosić wspólne konto biuro do nowego UI. Zgody i retencję planujemy jak w RODO w aplikacjach, bo przepisanie bez tego odtwarza ten sam audyt za rok.
Czego audyt nie jest
Nie jest certyfikatem ISO ani pieczątką zgodne z RODO. Nie zastępuje testów penetracyjnych red teamu w banku. Nie jest też pretekstem, żeby zawsze sprzedać nowy CRM. Czasem wynik brzmi: zaktualizujcie PHP, włączcie HTTPS, zróbcie kopie, rozdzielcie konta, dopiszcie 2FA na adminie — i żyjecie dwa lata bez rewrite. Czasem brzmi: ten kod nie ma testów, nie ma ról i nie ma autora; łatanie będzie droższe niż MVP. Mówimy to w raporcie, nie w ofercie na 200 godzin zanim zobaczymy repozytorium.
Jeśli działa, ale się boisz — to dobry moment na audyt, nie dzień po ataku. Napisz, jaki system chcesz sprawdzić: język, mniej więcej rok powstania, czy jest Git, czy ktoś administruje serwerem. Powiemy, czy wystarczy przegląd, czy od razu plan naprawy. Wycena po zakresie, bez ceny z katalogu za audyt bezpieczeństwa. Po pracach naprawczych albo nowym module dostajesz kod i 6 miesięcy gwarancji na ten zakres.
Na co patrzymy w starym PHP bez frameworka
Duża część paneli z lat 2012–2018 to nie Laravel, tylko skrypty z jednym plikiem konfiguracji, mysql_query albo starym mysqli bez bindingów, sesją w $_SESSION i uploadem do /uploads bez sprawdzania MIME. Tam SQL injection i XSS nie są hipotezą — są kwestią czasu i skanera. Audyt wtedy zaczyna się od inwentarza: ile jest wejść do bazy, czy hasła są w md5, czy admin to login w URL. Łatka bywa możliwa (prepared statements, escape, HTTPS, nowsze PHP), ale koszt rośnie liniowo z liczbą plików, których nikt nie mapował.
Szukamy też martwego kodu i backdoorów zostawionych po poprzednich włamaniach: pliki z losową nazwą w public, ocmin.php, maile wysyłane do obcego SMTP, cron, o którym nikt nie wie. To nie jest oskarżenie obecnego zespołu. To częsty obraz po dwóch zmianach freelancera i jednym tanim odzyskiwaniu po ransomware. Raport oddziela sprzątanie (usuń, zmień hasła, zrotuj klucze) od naprawy logiki. Bez tej kolejności nowy kod na brudnym serwerze nie ma sensu.
Wersja PHP jest twardym limitem. 7.4 i starsze nie dostają już poprawek bezpieczeństwa. Hosting, który trzyma 7.2 bo stary kod inaczej nie wstanie, jest decyzją biznesową o akceptacji ryzyka, nie o oszczędności. Mówimy to wprost w raporcie. Czasem jedyna uczciwa ścieżka to nowe środowisko na PHP 8 i Laravelu plus migracja danych, ze starym panelem w trybie tylko do odczytu przez kilka tygodni.
Jak czytamy raport razem z właścicielem
Każdy punkt ma: co się da zrobić z tą dziurą (w jednym zdaniu, bez CVE-poezji), kto musi ruszyć (kod, serwer, ludzie), co się stanie jeśli poczekacie kwartał. Krytyczne to rzeczy, które skaner albo student znajdzie w godzinę: otwarte .env, SQL w formularzu, admin bez hasła, backup w public. Ważne to brak 2FA na księgowości, wspólne konto, brak kopii poza serwerem. Warto poprawić to dług, który nie pali się dziś, ale zje kolejny sprint. Priorytetów nie mieszamy z upsellami.
Szacunek prac jest rzędem wielkości, nie rezerwacją kalendarza. Łatka CSRF i nagłówków to godziny. Rozdzielenie ról w kodzie, który ma if admin wszędzie, to tygodnie. Rewrite fragmentu logowania — osobny etap, z testami. Po raporcie możesz nic nie zlecać nam: dokument jest Twój. Jeśli zlecasz, wchodzimy w ten sam Git, z 6 miesiącami gwarancji na to, co ruszymy. Nie gwarantujemy, że w przyszłym miesiącu nie wyjdzie CVE w paczce, której dziś nie ma na liście.
RODO, logi i to, czego audyt bezpieczeństwa nie pomija
Przy panelach z kartotekami klientów audyt nachodzi na RODO: czy da się wykazać, kto eksportował, czy hasła i PESEL nie siedzą w logach, czy usunięcie konta zostawia śmieci w pięciu tabelach. To nie jest osobna usługa prawna. To pytania, bez których raport o XSS jest niepełny, bo wyciek i tak pójdzie przez uprawnienia i przez dump. Jeśli nie ma ról, nie ma zgód w bazie i nie ma retencji, zapisujemy to jako ryzyko projektowe, nie jako brak polityki w stopce.
Kopie zapasowe sprawdzamy praktycznie: czy da się odtworzyć na osobnej instancji, ile to trwa, czy kopia nie jest z zeszłego roku. W MŚP często jest cron na lokalny plik i nic poza serwerem. Ransomware albo pad dysku kasuje wtedy i produkcję, i backup. Rekomendacja bywa banalna i droga emocjonalnie: drugi storage, test raz na kwartał, hasło do kopii poza tym samym mailem co admin panelu. W raporcie to jest punkt z priorytetem, nie appendix.
Po audycie zostaje decyzja właściciela: łatamy teraz krytyczne, planujemy role na kwartał, przepisujemy logowanie, albo żyjemy ze świadomym ryzykiem. Świadome ryzyko też umiemy nazwać — byle nie udawać, że nic nie widzieliśmy. Jeśli wybierasz przepisanie, trzymamy stary panel pod twardszym hardeningiem (HTTPS, limity, zamknięte katalogi) na czas migracji. Git nowego kodu jest Twój od pierwszego commita na etapie, nie od faktury końcowej.
Jeśli nie masz kodu źródłowego (wykonawca zniknął, zostało tylko FTP), audyt i tak da się zacząć od serwera i zachowania aplikacji: nagłówki, wersje, otwarte panele, zachowanie formularzy. Reverse-engineering całego monolitu bez repozytorium jest droższy i to mówimy zanim wejdziemy. Czasem taniej jest spisać proces z ludzi i zrobić nowe MVP niż odtwarzać pięć tysięcy linii bez komentarza. To też jest wynik audytu, nie porażka. Wycena takiego scenariusza idzie po oględzinach, bez ceny katalogowej za odtworzenie cudzego PHP. NDA i tak podpisujemy przed wglądem w serwer.
Audyt, pentest i skaner — trzy różne usługi
Skaner (nikto, WPScan, composer audit) znajduje znane CVE i oczywiste misconfigi. Nie znajdzie IDOR na /faktura/1843 ani logiki „handlowiec widzi płace, bo w menu nie ma linku”. Test penetracyjny z zakresem ataku na produkcję to inna umowa, inne ryzyko i często wymóg ubezpieczyciela albo banku. Audyt GESOFT to przegląd kodu, zależności i serwera pod checklistą OWASP Top 10 2025: dostęp, konfiguracja, łańcuch dostaw, kryptografia, injection, projekt, auth, integralność, logi/alerty, wyjątki. Nie dostarczamy exploitów ani PoC na Twoją produkcję. Opisujemy ścieżkę tak, żeby dało się ją zamknąć.
To ważne prawnie i praktycznie: nie atakujemy systemu „żeby zobaczyć, jak daleko wejdziemy”. Potwierdzenie podatności — na kopii albo na teście, kontrolowanie. Celem jest lista z priorytetem, nie zrzut bazy w załączniku. Jeśli potrzebujesz red teamu z zakresem MITRE, powiemy, że to nie my, albo wskażemy inną ścieżkę. Nie sprzedajemy 80 stron PDF bez kolejności łatania.
Wersje PHP, CVE i twardy kalendarz wsparcia
PHP 7.4 stracił support bezpieczeństwa w listopadzie 2022, 8.0 w listopadzie 2023, 8.1 w grudniu 2025. 8.2 — poprawki bezpieczeństwa do grudnia 2026, 8.3 do grudnia 2027 (kalendarz php.net). Hosting na 7.2 albo 7.4 to otwarte drzwi niezależnie od jakości kodu biznesowego. Laravel 5.x i 6.x są poza cyklem: znane CVE w Symfony/Laravel nie dostaną backports na Twoją gałąź. W raporcie to jest punkt krytyczny albo „ważne — zaplanuj upgrade”, nie ozdobnik. Upgrade PHP na starym kodzie bywa tygodniami if-ów; czasem taniej jest MVP na PHP 8.3 i Laravelu.
composer audit / npm audit pokazują znane numery. Nie pokazują logiki. Porzucona paczka bez CVE też jest ryzykiem A03: nikt nie wyda patcha, gdy CVE wyjdzie. Lockfile w Git jest obowiązkowy do odtworzenia tego, co naprawdę stoi na produkcji. Brak lockfile = audyt zgaduje wersje. Sekrety w historii Gita (APP_KEY, hasło SMTP) traktujemy jako wyciek do rotacji, nawet jeśli „to było tylko na chwilę”.
IDOR, sesje i logowanie — checklista A01/A07 bez teatru
Sprawdzamy: czy ID w URL wystarczy do odczytu cudzego rekordu; czy cookie sesji jest HttpOnly/Secure; czy reset hasła enumeruje konta; czy brute-force nie jest nieskończony; czy wylogowanie kasuje sesję po stronie serwera; czy token API żyje wiecznie. To A01 i A07 z 2025. Wspólne konto „biuro” zapisujemy jako ryzyko RODO i bezpieczeństwa naraz: nie da się powiedzieć, kto wyeksportował, nie da się wyłączyć jednej osoby. Rekomendacja bywa organizacyjna (imienne konta, 2FA na adminie) zanim ruszamy kod.
Raport oddajemy w języku właściciela i administratora. Krytyczne — zamknij w dniach. Ważne — w tym kwartale. Dług — przy okazji funkcji. Szacunek prac jest rzędem, nie rezerwacją kalendarza. Po raporcie możesz nic nie zlecać: dokument jest Twój. Jeśli zlecasz łatki albo fragment na Laravelu, wchodzimy w Git z 6 miesiącami gwarancji na to, co ruszymy. Napisz język, rok powstania i czy jest repozytorium — widełki audytu po rozmowie, bez ceny katalogowej.
Najczęściej zadawane pytania
- Co obejmuje audyt bezpieczeństwa PHP?
- Aplikację (logowanie, formularze, uprawnienia), zależności (PHP, Laravel, CVE) i serwer (HTTPS, .env, kopie). Wynik to lista z priorytetem, nie straszak na 80 stron.
- Czy potrzebujecie haseł produkcyjnych?
- Kod (Git lub archiwum) i konto z ograniczonymi uprawnieniami albo rozmowa z administratorem. NDA na start. Haseł do bazy nie wysyłaj mailem.
- Kiedy łatamy, a kiedy przepisujemy?
- Łatamy, gdy logika jest jasna, a dziury da się zamknąć aktualizacją. Przepisujemy przy porzuconym PHP w jednym pliku albo gdy RODO wymaga nowego modelu danych.
- Ile trwa audyt typowego panelu?
- Zwykle kilka dni roboczych. Większe monolity — po oględzinach zakresu. Raport w ustalonym terminie, nie w nieskończonym discovery.
- Czy to jest test penetracyjny?
- To przegląd kodu, konfiguracji i zależności pod checklistą OWASP. Nie prowadzimy widowiskowego ataku na produkcję i nie dostarczamy exploitów. Jeśli wyjdzie dziura, opisujemy ją tak, żeby dało się ją zamknąć.
- Ile kosztuje audyt?
- Zależnie od wielkości kodu i czy sprawdzamy serwer. Nie ma jednej ceny katalogowej. Napisz, jaki system i w jakim języku — damy widełki po krótkiej rozmowie.
- Co jeśli wyjdzie, że trzeba pisać od nowa?
- Dostajesz to na piśmie z uzasadnieniem, nie jako presję. Możesz łatami iść dalej, zlecić nam MVP albo wziąć raport do innego zespołu. Kod źródłowy audytu (notatki, skrypty pomocnicze) nie zastępuje Twojego repozytorium.
- Czy po poprawkach jest gwarancja?
- Na prace, które wykonamy (łatki albo nowy fragment), dajemy 6 miesięcy gwarancji i przekazanie w Git. Sam raport nie jest gwarancją, że nikt nigdy nie znajdzie nowej klasy błędu — świat CVE się kręci.
Powiązana usługa:
Aplikacje Laravel i Vue.js
Opisz projekt