Security w sklepie B2B - WAF, rate limiting, ochrona API
Sklep B2B jest cenniejszym celem niż B2C i większość właścicieli się tego nie spodziewa. Cennik kontraktowy konkurenta wart jest więcej niż listy mailingowe, a jedno zalogowane konto kontrahenta daje boczne wejście do limitów kredytowych i historii zamówień. Widziałem sklepy, którym konkurencja pobrała kompletny cennik 80 tys. SKU w weekend - bo nikt nie założył rate limita na endpoint katalogu. WAF, rate limiting po koncie i monitoring anomalii to nie luksus, tylko higiena - inaczej w pierwszym roku tracisz dane, a w drugim klientów, którzy zobaczyli twój cennik u kogoś innego.
Spis treści (6)
Realne zagrożenia w sklepie B2B
Posortowane po faktycznej szkodzie, którą widziałem u klientów, a nie po atrakcyjności prasowej. Większość rankingów OWASP traktuje wszystkie zagrożenia po równo. Dla sklepu B2B kolejność jest inna.
Pierwsze i najczęstsze to scrapowanie cennika. Konkurent loguje się na własne konto (czasem kupione z drugiej ręki, czasem założone w piątek na podstawione dane firmy) i przez weekend ściąga całą bazę cenową przez API katalogu. Sklep widzi w poniedziałek anomalię w logach, ale szkoda już się stała - cennik krąży po rynku. To nie jest atak rozumiany jako "włamanie", tylko legalna sesja zalogowanego użytkownika. WAF tego nie zatrzyma, jeśli nie ma limitu po koncie.
Drugie to credential stuffing. Boty biorą bazę haseł z wycieku z forum motoryzacyjnego sprzed roku i testują w sklepie. W B2C zdobycie konta to dostęp do historii zakupów. W B2B - do cennika kontraktowego, limitów kredytowych, danych innych kupujących z tej samej firmy. Wartość wielokrotnie wyższa.
Trzecie to carding na endpoincie płatności. Sklep, który ma Stripe albo Tpay włączony, jest darmowym testem dla kradzionych kart. Tysiąc prób na minutę, do drugiej godziny operator płatności blokuje konto sprzedawcy "za podejrzane wzorce". Klient autentyczny wchodzi i nie może zapłacić, bo brama jest zawieszona.
Czwarte to DDoS celowany w drogie endpointy - wyszukiwarkę pełnotekstową, konfigurator produktu, kalkulator wysyłki paletowej. Wolumetryczny ruch ogarnia CDN. Celowane 50 requestów na sekundę w konfigurator, który po stronie aplikacji robi pięć zapytań do bazy i policzenie kosztów dostawy, wywróci sklep w piętnaście minut.
Piąte i szóste są niżej, ale wciąż realne. SQL injection albo XSS w custom module pisanym pod jednego klienta bez review - klasyk Magento, gdzie dział partnera dorabia integrację na fakturę i nikt nie patrzy w kod. Wycieki przez integracje to nawet nie atak - to brak higieny. Token API do ERP wrzucony do commita "fix env vars", klucz Akeneo wyciekły do pliku log, który Sentry zaindeksował publicznie.
WAF managed vs self-hosted
Dla 95% sklepów B2B w Polsce odpowiedź brzmi Cloudflare, i dyskusja na tym powinna się skończyć. Mówię to po kilku wdrożeniach, w których ktoś chciał ambitnie postawić ModSecurity z OWASP CRS na własnym Nginxie, a po pół roku zespół DevOps zrezygnował z reguł, bo każdy false positive trafiał do nich osobiście.
Plusy managed (Cloudflare, AWS WAF, Akamai) są banalne: płacisz miesiąc, reguły OWASP są gotowe, nowe wjeżdżają same, panel ma dashboard, który zrozumie też head of e-commerce. Cloudflare Free wystarczy do startu małego sklepu. Pro za około 20 USD miesięcznie odblokowuje custom rate limiting i WAF rules, których realnie potrzebujesz. Business i Enterprise to próg, który ma sens dopiero przy 100 tys. dziennych wizyt albo wymogach compliance.
Minus jest jeden, ale rzeczywisty: kilka godzin opóźnienia między publikacją CVE a aktualizacją reguł. Dla większości sklepów to akceptowalne. Jeśli grasz w niszy, gdzie konkurencja stać na celowane uderzenia w okno zero-day, to i tak będziesz miał własny SOC, nie ModSecurity na produkcji.
Self-hosted (ModSecurity, OpenAppSec, Coraza) ma sens w dwóch sytuacjach. Pierwsza - musisz hostować on-premise z powodów regulacyjnych (rzadkie w polskim B2B, częstsze w sektorze publicznym i medycznym). Druga - masz zespół security w pełnym wymiarze, który to utrzyma. Bez tego ModSecurity zamienia się w "włączone, ale nikt nie ogląda alertów".
Decyzja dla typowego sklepu 30-80 tys. SKU: Cloudflare Pro lub Business, reguły OWASP managed włączone, plus 5-10 custom rules na endpointy, które ty znasz, a Cloudflare nie - login, API katalogu, koszyk, konfigurator. To załatwia 90% przypadków za 20-200 USD miesięcznie.
Rate limiting warstwowy
Jedna globalna reguła "100 requestów na minutę z IP" to gorzej niż brak. Brak limitów jasno mówi "nie chronię tego", a źle ustawiony limit daje fałszywe poczucie bezpieczeństwa i blokuje klientów, którzy mają VPN korporacyjny z dziesiątkami buyerów za jednym IP. Skuteczny rate limiting ma cztery warstwy, i każda mierzy inną rzecz.
Pierwsza to edge na CDN. W Cloudflare wygląda to tak:
Rule: API katalogu - 60 req/min per IP, action: challenge
Rule: Login endpoint - 5 req/min per IP, action: block 15min
Rule: Search endpoint - 30 req/min per IP, action: challenge
Challenge jest istotny - to nie blokada, tylko CAPTCHA. Bot odpada, klient z VPN-em pstryknie checkbox i wchodzi dalej. Block ma sens tylko na login i jednoznacznie destrukcyjne endpointy.
Druga warstwa to limit po koncie zalogowanym, nie po IP. Hurtownia narzędzi z 50 buyerami za jednym firmowym IP potrzebuje limitu trzykrotnie wyższego niż anonimowy gość, ale ten limit musi być policzony per użytkownik, nie zbiorczo. W Laravelu to wygląda trywialnie:
RateLimiter::for('api-katalog', function (Request $request) {
return $request->user()
? Limit::perMinute(300)->by($request->user()->id)
: Limit::perMinute(30)->by($request->ip());
});
Trzecia warstwa to limit per endpoint biznesowy. Pobranie cennika całego katalogu nie może mieć tego samego limitu co pobranie szczegółów jednego produktu - to dwa rzędy wielkości różnicy w koszcie po stronie sklepu. Endpoint na export katalogu wystawiam zwykle z limitem typu "5 razy dziennie per konto, plus alert do zespołu po piątym".
Czwarta to detekcja anomalii, nie sztywna reguła. Klient kontraktowy ma własny profil - kupuje średnio 12 razy w tygodniu, pobiera cennik 2-3 razy w miesiącu, loguje się z jednego-dwóch IP. Skok do 200 zapytań do API w godzinę z czterech nowych IP to alert do zespołu, nie automatyczna blokada. Auto-block w takich przypadkach kończy się telefonem szefa zakupów do twojego prezesa.
Ochrona cenników kontraktowych
Cennik kontraktowy jest danym wrażliwym biznesowo. Większość sklepów to wie, ale traktuje to tak samo jak ochronę listy klientów - przez login. To za mało. Standardowa konfiguracja Magento wystawia cennik przez API katalogu w sposób, który da się zescrapować skryptem w Pythonie napisanym przez stażystę.
Chronię konkretnie cztery rzeczy. Endpoint listy produktów z cenami (GET /api/products?customer_id=X), bo to brama do całości. Endpoint kalkulacji ceny dla ilości, bo z niego konkurent wyciąga progi rabatów ilościowych, które nigdy nie miały być publiczne. Export do PDF i Excel, bo plik łatwo udostępnić dalej. Eksport PunchOut, bo idzie do systemu klienta i tam żyje poza twoją kontrolą.
Mechanizmy obrony układają się w piramidę. Na dole twarde limity na pobieranie wsadowe - maksymalnie 200 produktów na request, paginacja wymuszona, brak ?per_page=99999. Wyżej watermarking: w każdym wygenerowanym PDF i Excelu siedzi ukryty identyfikator kontrahenta i timestamp generowania. Kiedy cennik wycieka, wiesz, od kogo. Jednorazowo poznałem hurtownię, która w ten sposób udowodniła, że dealer sprzedał cennik konkurencji za 15 tys. zł - bo PDF miał metadanę z jego ID.
Wyżej behavioral analysis. Realny klient B2B pobiera cennik dwa-trzy razy w tygodniu, nie pięć razy na minutę. Anomalia powyżej własnej średniej z 30 dni to soft block - czyli wymóg potwierdzenia mailem lub SMS-em, że to faktycznie on. MFA na konta z dostępem do całego cennika to ten sam koszt co lunch i podnosi poprzeczkę o rząd wielkości.
Na samej górze logowanie pobierania. Każde wywołanie zapisuje krotkę (user, IP, liczba rekordów, hash treści). Audyt po incydencie ma materiał - bez tego nie udowodnisz nawet sobie, kto wziął co.
Cenniki kontraktowe per kontrahent - osobny temat, ale ściśle powiązany.
Bezpieczeństwo API i tokenów
Tokeny do integracji - ERP, PIM, OMS, bramka płatności - to drugi po cenniku najczęściej zaniedbany obszar. Higiena minimum, którą wymuszam na każdym audycie, to cztery rzeczy: każdy token ma zawężony scope (read-only do PIM, write tylko do tabeli zamówień w ERP), rotacja co 90 dni z alertem 14 dni przed wygaśnięciem, tokeny nigdy w kodzie ani w gicie tylko w secret managerze (Vault, AWS Secrets Manager, Doppler), oraz audit log "kto kiedy używał".
Endpointy wystawione na zewnątrz mają trzy regularne grzechy. Webhooks od bramki płatności bez walidacji sygnatury HMAC i bez IP allowlistu - klasyka. Każdy może wysłać POST udający Tpay i zaznaczyć zamówienie jako opłacone. Drugi grzech to publiczne API sklepu bez API key per integrator - nie da się unieważnić tylko jednego klienta, trzeba rotować klucz globalnie. Trzeci to endpointy administracyjne na publicznej domenie. /admin osłonięty samym hasłem to zaproszenie do bruteforce - osobna subdomena za VPN-em lub CIDR allowlist to dziesięć minut konfiguracji, które zamykają cały atak frontalny.
Z OWASP API Top 10 trzy błędy widzę regularnie. Broken Object Level Authorization - /api/order/123 zwraca cudze zamówienie po zmianie ID, bo backend sprawdza tylko, że jesteś zalogowany, a nie że to twoje zamówienie. Excessive Data Exposure - API zwraca wszystkie pola modelu (łącznie z cost_price, margin, supplier_id), frontend filtruje co wyświetlić, a Postman pokazuje wszystko. Lack of Resources Limiting - brak limitu wielkości response. Wystarczy ?per_page=1000000 i sklep się dusi.
False positive blokujące klientów
Najgorsze, co WAF może ci zrobić, to zablokować klienta, który ma w koszyku za 80 tys. zł. Każdy taki przypadek to telefon na infolinię, dłuższa rozmowa, zwykle przeproszenie i jednorazowo - utracone zamówienie u kogoś, kto miał zostać u ciebie przez następne pięć lat. Skala szkód z false positive jest większa niż większości realnych ataków, które WAF łapie.
Cztery klasyki, które zawsze sprawdzam po wdrożeniu nowych reguł. Quick order CSV z 5 tys. SKU - request POST o wielkości 500 kB blokowany przez generyczne "request size anomaly". Klient wkleja gotowy plik z Excela i widzi 403. Klient kopiujący tabelę z Excela do koszyka jeden produkt po drugim - tysiąc kliknięć w sekundę wygląda jak bot, choć to faktycznie kupujący z palcami szybszymi niż średnia. VPN korporacyjny - sto buyerów za jednym IP, w WAF widać jak DDoS. PunchOut - cykliczne requesty z SAP-a klienta sklasyfikowane jako scraper.
Łagodzenie układa się tak: allowlist IP zaufanych kontrahentów (zbieram je na onboardingu razem z firmowymi danymi), wyższe limity dla logowanych kont, dedykowany endpoint dla quick order z osobnym limitem, monitoring 4xx z perspektywy klienta. Ostatnie jest ważne - większość zespołów monitoruje 5xx (błędy serwera), a nie 4xx, ale to właśnie skok 4xx oznacza zablokowanego klienta.
Miernik praktyczny: procent zablokowanych requestów, które po analizie okazują się ruchem legitnym. Jeśli przekracza 5%, reguły są źle skalibrowane i czas przejść z block na challenge albo podnieść próg.
FAQ
Czy darmowy Cloudflare wystarczy dla sklepu B2B? Dla startu i sklepu poniżej 10 tys. miesięcznych wizyt - tak. Powyżej tej skali brakuje custom rate limiting rules i Bot Fight Mode bez Pro. Realnie Pro za 20 USD miesięcznie spina większość przypadków, które widziałem. Business ma sens dopiero przy 100 tys. dziennych wizyt albo wymogu SLA, którego Pro nie daje.
Jak długo trwa wdrożenie pełnego stack security w sklepie B2B? Cloudflare z gotowymi regułami OWASP plus podstawowy rate limiting po IP - tydzień, większość to konfiguracja DNS i czekanie na propagację. Pełne wdrożenie z behavioral analysis, MFA na kontach z dostępem do cennika, rotacją tokenów i logowaniem audytowym - 4-8 tygodni na Magento 2.4 z 30-80 tys. SKU. Plus dwa-trzy miesiące kalibracji false positive, zanim reguły faktycznie nie przeszkadzają klientom.
Czy WAF zastąpi dobrze napisany kod aplikacji? Nie i nigdy nie zastąpi. WAF łapie znane wzorce, ale nowe SQL injection w custom module pójdzie do bazy. WAF to warstwa, którą dodajesz na wierzchu kodu, który już jest bezpieczny - nie zamiast review i nie zamiast parametryzacji zapytań.
Jak chronić sklep przed atakami z polskich IP, których nie można zablokować geograficznie? Trzy rzeczy razem. Reputation lists (Cloudflare wbudowane, AbuseIPDB dodatkowo) odsiewają znane złe IP. Wymóg potwierdzenia konta mailem z domeny firmowej blokuje boty zakładające konta na Gmaila. Behavioral analysis łapie konta świeże, które od razu próbują dużych zakupów albo masowo pobierają cennik - alert, nie automatyczna blokada.
Czy zgodność z RODO wymaga konkretnych narzędzi WAF? RODO mówi o "odpowiednich środkach technicznych i organizacyjnych", nie o konkretnym produkcie. WAF, monitoring i audit log to dokumentowalna odpowiedź, którą pokazujesz inspektorowi przy kontroli. Dokumentacja jest ważniejsza niż wybór dostawcy - musisz umieć powiedzieć, jakie ataki blokujesz i jak to weryfikujesz.
Co dalej
- Architektura sklepu B2B: Architektura dużych sklepów B2B
- CDN przed sklepem: CDN dla katalogów
- Ochrona danych cennikowych: Cenniki kontraktowe per kontrahent
O autorze
Jakub Owsianka
Architekt rozwiązania w WiseB2B - silniku platform B2B. Zaczynał po stronie biznesu (własne sklepy), potem deweloper, dziś projektuje wdrożenia dla sklepów z katalogami w dziesiątkach tysięcy SKU. W ostatnich latach wdrożył AI-development w zespole i funkcjonalności oparte o AI bezpośrednio w silniku sklepu.
Masz pytanie do tego artykułu?
Dodatkowy kontekst, problem z własnym wdrożeniem, druga opinia - napisz wprost. Odpowiadam osobiście w 1-2 dni robocze.