Blog

Wpisy

Bezpieczeństwo sklepów e‑commerce — trzy wektory, które widuję w praktyce

Credentials do panelu, skimmer ukryty za „bugiem” checkoutu i injection w polu komentarza — co łączy realne incydenty i jaką checklistę z nich biorę.

Przy sklepach, przy których pracuję, włamania rzadko wyglądają jak w filmie. Nie ma hollywoodzkiego zero-daya na ekranie. Jest sesja w panelu, dziwny checkout, albo próba wstrzyknięcia kodu w pole, którego nikt nie uważa za „powierzchnię ataku”.

Poniżej trzy anonimowe case’y — różne platformy, różne wektory, jeden wspólny wniosek: sygnał biznesowy bywa pierwszym alertem bezpieczeństwa, a po incydencie liczy się nie tylko cleanup, ale dokumentacja (w tym pod RODO). Bez payloadów, bez haseł i bez identyfikatorów klientów.

Zanim przejdę do chronologii: w ekosystemie PHP / e‑commerce te historie rzadko zaczynają się od „magicznego” zero-daya. Najczęściej w tle leży coś z tej listy — brak 2FA w panelu, słabe albo współdzielone poświadczenia (panel, SSH/SFTP, FTP), zaległe update’y core i pluginów/modułów, albo supply chain: niesprawdzona wtyczka / motyw z marketplace’u, który wnosi podatność albo złośliwy kod. Case’y poniżej to konkretne scenariusze na tym podłożu.

Case 1: panel WordPressa, skradzione hasło, malware w pluginach

Średni sklep na WordPress + WooCommerce. Klasyczny setup: dane klientów w zamówieniach, Cloudflare przed hostingiem, panel admina jako główny punkt sterowania.

W nocy atakujący wszedł do panelu, wgrał zestaw typowy dla post-compromise: webshell, plugin utrzymujący ukrytego admina oraz downloader (ten ostatni w logach wyglądał na nieużyty). Aktywność trwała kilkanaście godzin; wykrycie przyszło w południe — nietypowe pliki i zepsuty panel. Cleanup zajął ok. godziny; potem hardening i dokumentacja.

Przyczyna

Najbardziej prawdopodobny wektor: skompromitowane dane logowania (infostealer / wyciek), nie łamanie CAPTCHA. Alternatywa — stary, niezałatany komponent sklepu — była rozważana, ale bez twardego dowodu. Logi WAF/CDN pokazywały aktywność z panelu, w tym ścieżkę uploadu pluginów.

Skutki

  • nieautoryzowany dostęp do admina i persistence w wp-content,
  • ryzyko dla danych osobowych (potencjalny dostęp istniał),
  • zepsuty panel jako paradoksalny sygnał wykrycia — jeden z komponentów przerywał normalne wykonanie kodu.

Co sprawdziłem pod kątem danych klientów

Potencjalny dostęp ≠ automatycznie naruszenie ochrony danych. Ocenę oparłem o logi: brak nietypowych połączeń wychodzących, brak skoku wolumenu, brak ścieżek typowych dla dumpów DB w ruchu atakującego, malware nie wyglądał na celowaną eksfiltrację. Wniosek dokumentacyjny: niskie ryzyko + szybka reakcja → uzasadnienie braku zgłoszenia do UODO (art. 33), ale z notatką, timeline’em i analizą z IOD — nie „zignorujemy temat”.

Przeciwdziałanie

Contain → eradicate → harden → document. Zanim cokolwiek skasuję na żywej instancji, robię szybki snapshot / image (dysk + stan bazy) — materiał pod analizę śledczą i zabezpieczenie przed utratą spójności danych. Dopiero potem: usunięcie artefaktów i konta atakującego, warstwa przed panelem (htpasswd), blokada zapisu w katalogu pluginów, zmiana hasła bazy, update core i pluginów, skaner/WAF z alertami, ukrycie URL logowania, rotacja haseł (w tym htpasswd), 2FA dla adminów, backup 3-2-1 z retencją logów, audyt kont FTP/WP i spisane procedury. Nie zostawiłem tego na „później” — hardening poszedł razem z cleanupem.

Lekcja: większość włamań do sklepów WP, które widuję, to nadal credentials + panel, nie egzotyczny exploit.

Case 2: „bug kodu rabatowego”, a pod spodem Magecart + RCE

Inny sklep — PrestaShop. Zgłoszenie od klienta brzmiało jak pilny ticket UX: kod rabatowy w koszyku od razu przenosi do płatności; część zamówień bez numeru telefonu; „płatność się nie udaje”. Po chwili analizy okazało się, że to nie regres checkoutu.

Co się działo naprawdę

Uproszczony kill chain:

  1. Rekonesans — nocne skany pod typowe webshelle i ścieżki platformy.
  2. RCE — aktywny shell w cache znanego modułu (katalog cache z wykonywalnym PHP).
  3. Eskalacja — lokalizacja pliku konfiguracyjnego → credentials bazy → zapytania KPI (nie pełny dump klientów przez ten kanał).
  4. Monetyzacja — osobny tor: skimmer udający warstwę płatności (loader w head + endpoint „GTM-like” na obcej domenie). Zbierał dane klienta i karty; po kradzieży „płatność fail”, skrypt nie odpalał drugi raz.

Okno skimmera: od wgrania plików do usunięcia — rzędu dni, bo pierwszy sygnał wyglądał jak bug frontu.

Przyczyna / skutki

Przyczyna: przestarzały / podatny moduł + cache traktowany jak bezpieczne miejsce na kod. Skutki: RCE (utrzymanie dostępu, wycena sklepu) i skimmer kart (osobna szkoda). Brak dumpa klientów w SQL nie oznacza braku szkody — karty poszły innym kanałem.

Przeciwdziałanie

Usunięcie skimmera i loaderów, weryfikacja motywów/modułów pod reinfect, patch podatnego modułu, natychmiastowa rotacja hasła DB (credentials już były w rękach atakującego), reset haseł BO, audyt uploadów. Zamiast ślepego kasowania ścieżki shella — honeypot łapiący powroty. Biznesowo-prawnie: okno zamówień pod RODO/UODO, kontakt z operatorem płatności przy wycieku kart.

Lekcja: nietypowy checkout + dziwna walidacja to red flag bezpieczeństwa, nie tylko QA. RCE i Magecart to dwa cele — remediacja musi pokryć oba.

Case 3: injection w komentarzu do zamówienia (custom)

Trzeci przypadek jest prostszy i przez to ważny. W sklepie custom ktoś próbował przez komentarz do zamówienia wstrzykiwać JavaScript, PHP i SQL. Pierwsze payloady wyglądały na probing — sprawdzenie, czy injection w ogóle działa. Część skryptów w ogóle nic nie zrobiła; jedyny, który „przeszedł” zapis, pojawił się w adminie jako tekst — i na tym się skończyło. Nie było tu przypadku: treść komentarza przy renderze w BO szła przez escapowanie HTML (oraz sanityzację przy zapisie). Przeglądarka dostała bezpieczny string, nie wykonywalny kod, więc XSS w panelu nie wystartował.

Przyczyna / skutki / przeciwdziałanie

Przyczyna: pole treści użytkownika traktowane jak niewinne — a trafia do BO. Skutki: przy braku escapowania to klasyczny XSS w panelu (sesja admina, kradzież cookie, dalsza eskalacja). Przeciwdziałanie: escape przy wyświetlaniu, walidacja przy zapisie, CSP tam gdzie ma sens, przegląd wszystkich miejsc, gdzie treść zamówienia ląduje w HTML.

Lekcja: powierzchnia ataku to nie tylko /admin/login. To każde pole, które kiedyś zobaczy pracownik w panelu.

Co łączy te trzy historie

Case 1 (WP) Case 2 (Presta) Case 3 (custom)
Pierwszy sygnał zepsuty panel / dziwne pliki „bug” checkoutu probing w komentarzu
Wejście credentials → panel RCE w module/cache injection w polu BO
Cel persistence / dostęp skimmer kart + shell test podatności / XSS
Remediacja cleanup + harden + RODO paper patch + rotacja secretów + honeypot escape + walidacja

Wspólne zasady, które stosuję przy e‑commerce:

  1. Traktuj dziwny UX jak potencjalny incydent — dopóki nie wykluczysz malware.
  2. Najpierw kopia forensyczna, potem sprzątanie — snapshot/image żywej instancji (i bazy) przed eradicate; inaczej gubisz dowody i ryzykujesz niespójność danych.
  3. Credentials są spalone szybciej, niż myślisz — po RCE lub wycieku configa rotuj DB i konta od razu, nie „po sprzątaniu JS”.
  4. Cache i uploady to kod — jeśli PHP da się tam wykonać, to wektor.
  5. Każde pole użytkownika w BO to XSS waiting to happen bez escapowania.
  6. Contain → eradicate → harden → document — bez ostatniego kroku nie masz historii pod IOD / UODO / ubezpieczyciela.
  7. Próba naruszenia systemu ≠ automatycznie naruszenie danych — ale ocena musi być spisana, nie „na czuja”.

Checklista, którą zostawiam po takich sprawach

  • Snapshot / image przed jakimkolwiek cleanupem na produkcji
  • 2FA (albo druga warstwa) dla wszystkich adminów — oraz twarde hasła / rotacja SSH·SFTP·FTP
  • Regularne update’y core, motywów i modułów — szczególnie tych z cache/upload; wtyczki tylko z zaufanego źródła
  • Skaner integralności plików + alerty
  • Backup 3-2-1 i retencja logów (access + WAF/CDN)
  • Escape/sanitization wszystkich treści użytkownika w panelu
  • Rotacja secretów po każdym potwierdzonym RCE / wycieku configa
  • Procedura: kto ogłasza incydent, kto spisuje timeline, kto rozmawia z IOD
  • Po skimmerze kart: kontakt z operatorem płatności, nie tylko „wyczyść JS”

Podsumowanie

Bezpieczeństwo sklepu to nie jeden produkt WAF i nie jeden plugin. To nawyk: czytać nietypowe zachowanie frontu jako sygnał, zakładać że panel padnie przez hasło, a nie przez zero-day, i po sprzątaniu zostawić papier, nie tylko czysty dysk. Trzy powyższe case’y są zanonimizowane, ale powtarzalne — credentials, Magecart za „bugiem”, injection w niewinnym polu. Takie rzeczy widuję częściej niż spektakularne zero-daye. I właśnie dlatego warto mieć playbook zanim ktoś zadzwoni z „pilnym bugiem w koszyku”.