Jak zabezpieczyć aplikację webową, której nie rozumiesz do końca
Gdzieś tam jest aplikacja webowa, za którą odpowiadasz, i nikt nie potrafi Ci z poważną miną powiedzieć, czy formularz logowania można bezpiecznie wystawić do internetu. Może aplikację odziedziczyłeś. Może kolega naklepał ją przez weekend. Może ma dziesięć lat, a pierwotnego zespołu dawno nie ma. Wszystko to jest tym samym problemem: musisz zabezpieczyć aplikację webową, której wnętrza nie rozumiesz do końca. Nie możesz przejść przez każdą trasę, każde sprawdzenie uwierzytelnienia, każdą zależność i każde zapytanie do bazy i osobiście za nie zaręczyć. Przepisanie zajmuje kwartały, których nie masz, a zostawienie tego wystawionego jest nie do przyjęcia. O tym środku właśnie jest ten artykuł.
Gdy pełny audyt nie jest od razu możliwy, kilka zabezpieczeń może ograniczyć ekspozycję podczas poznawania aplikacji. Zacznij od publicznych punktów wejścia, danych wrażliwych i uprawnień. Artykuł skupia się na trzech uzupełniających się kontrolach:
| Warstwa | Co robi |
|---|---|
| Skanowanie sekretów | Znajduje poświadczenia, które wyciekły do repozytorium i jego historii. |
| Filtrowanie na brzegu | WAF przed aplikacją, filtrujący jawnie złośliwy ruch. |
| Ochrona przed botami | CAPTCHA albo detekcja botów na podstawie wyniku na formularzach, które muszą pozostać publiczne. |
Skanowanie sekretów analizuje repozytorium i historię. WAF filtruje ruch przed aplikacją. Ochrona przed botami ogranicza automatyczne nadużycia. Działają na różnych poziomach i nie dowodzą bezpieczeństwa samej aplikacji.
Wirtualna łatka blokuje wykorzystanie konkretnej podatności bez zmiany podatnego kodu, np. celowaną regułą WAF. To jedno z zastosowań filtrowania, a nie nazwa wszystkich opisanych zabezpieczeń.
Brzeg to miejsce, w którym ten artykuł spędza większość czasu, ale omówimy też trochę tego, co można zrobić za brzegiem — patrząc zamiast tego w środek: na biblioteki, które aplikacja faktycznie uruchamia, na jej kod źródłowy i na jej zachowanie w czasie działania. Skanowanie zależności znajduje biblioteki ze znanymi lukami, które aplikacja już ze sobą wozi, a SAST i DAST na końcu artykułu wyłapują wzorce na poziomie kodu, których nie widzi żadna warstwa brzegowa.
Większość tych warstw ma solidną opcję do samodzielnego hostowania, działającą na dowolnym hoście — gitleaks do sekretów, ModSecurity do WAF-a, OSV-Scanner do zależności, Semgrep do SAST, ZAP do DAST. Te pozostają wiodące przez cały tekst. Co do zarządzanych odpowiedników w chmurze — gdzie wymieniasz część pracy konfiguracyjnej na dostrojony przez dostawcę zestaw reguł i jego wiedzę o zagrożeniach — swoje ma każda duża chmura. Jako konkretny punkt odniesienia, gdy zarządzany przykład pomaga, sięgniemy po Google Cloud Platform: Cloud Armor do WAF-a, Artifact Analysis do skanowania kontenerów, reCAPTCHA Enterprise i Adaptive Protection do obrony przed botami. Wybór jednej chmury czyni te przykłady konkretnymi, a nie machnięciem ręką; AWS, Azure i Cloudflare mają odpowiedniki, o których wspomnimy krótko, ale nie zejdziemy w nie głęboko.
Trzy kategorie nieznanego
Przed narzędziami warto nazwać, przed czym właściwie się bronisz, bo to kształtuje, która warstwa ma największe znaczenie. Nieznane rozpada się na trzy grupy.
Co jest w kodzie i w repozytorium. Nie wiesz, które trasy istnieją — aplikacje odziedziczone rosną organicznie i są tam prawdopodobnie endpointy administracyjne, o których nikt nie wspomniał. Nie wiesz też, co kod właściwie robi, bo albo nie zdążysz go przeczytać (legacy), albo nikt go za pierwszym razem uważnie nie czytał (wygenerowany przez AI). I nie wiesz, co już wyciekło do historii gita. DAST sonduje działającą aplikację z zewnątrz, by zmapować to, co jest faktycznie wystawione; SAST daje niepełną, ale użyteczną mapę ryzykownych wzorców kodu; skanowanie sekretów wyłapuje poświadczenia zapomniane w starych commitach.
Zależności. Stare lub nieutrzymywane biblioteki mogą zawierać znane podatności. Inwentaryzacja i skaner pomagają wskazać wersje, lecz wyniki trzeba ocenić względem rzeczywistej ekspozycji aplikacji.
Ruch produkcyjny. Logi żądań i WAF mogą ujawnić wzorce ataków oraz fałszywe alarmy. Dają częściowy obraz, nie pełną wiedzę o atakujących ani dowód nieszkodliwości nieoznaczonego ruchu.
Żadne narzędzie nie rozwiązuje wszystkich tych rzeczy. Każda z trzech warstw poniżej adresuje jedną albo więcej z nich; skanowanie zależności (omówione po warstwach) i SAST/DAST (na końcu) pchają głębokość dalej, gdy podstawy są już na miejscu.
Skanowanie sekretów
Poświadczenia trafiają do kodu, konfiguracji, danych testowych i dokumentacji. Usunięcie wartości z bieżącego pliku nie usuwa jej ze starszych commitów, dlatego sprawdzaj historię i aktualne pliki.
Przeskanuj odpowiednią historię, zbadaj wyniki i unieważnij lub obróć rzeczywiście ujawnione poświadczenia. Dodaj kontrole nowych zmian w CI.
Narzędzia
- gitleaks — szybki, w Go, ze znakomitymi domyślnymi regułami pokrywającymi większość dostawców (AWS, GCP, Azure, Stripe, Twilio, tokeny GitHuba, klucze prywatne, JWT). Uruchamiaj go na pełnej historii, nie tylko na HEAD.
- trufflehog — podobna detekcja, ale dodaje krok weryfikacji: sprawdza, czy wykryty sekret jest faktycznie żywy (np. wykonuje wywołanie
sts:GetCallerIdentitydla kluczy AWS). Wyjście o wyższym sygnale, dodatkowe opóźnienie tego warte. - git-secrets — nastawiony na AWS, lekki, przydatny jako hook pre-commit.
- GitHub Secret Scanning — darmowy dla repozytoriów publicznych, Advanced Security dla prywatnych. Dostawcy mogą unieważniać wykryte tokeny; potwierdź to zamiast zakładać automatyczne unieważnienie.
Uruchamiamy skan i czytamy wyjście
gitleaks da się zainstalować na kilka sposobów — gotowy plik binarny, Homebrew, go install albo przez Dockera. Użyjemy tu Dockera dla wygody: nic nie trzeba instalować na hoście, ta sama komenda działa na dowolnej maszynie z demonem Dockera, a runnery CI dostają to samo wywołanie co Twój laptop.
Właśnie uruchomiłem to na repozytorium, w którym żyje ten artykuł:
docker run --rm -v "$(pwd):/repo" zricethezav/gitleaks:latest \
git /repo --log-opts="--all" --redact --verbose--log-opts="--all" przechodzi przez każdy commit na każdej gałęzi, nie tylko HEAD; --redact maskuje wartość sekretu w wyjściu, żeby sam raport nie stał się nowym wyciekiem; --verbose wypisuje pełny blok dla każdego znaleziska, a nie tylko zbiorczy licznik.
gitleaks emituje jedno znalezisko na każdy potencjalny łańcuch-sekret, który rozpozna — ten sam zestaw pól dla każdego dopasowania, niezależnie od tego, która reguła odpaliła. Typowe znalezisko wygląda tak:
Finding: STRIPE_SECRET_KEY=REDACTED
Secret: REDACTED
RuleID: stripe-access-token
Entropy: 4.175736
File: blog/src/content/blog/anatomy-of-a-developer-targeted-supply-chain-attack.mdx
Line: 225
Commit: 49e4ca23a5ee6d1ef6b1a566a580a4086fbb84aa
Fingerprint: 49e4ca23a5ee6d1ef6b1a566a580a4086fbb84aa:blog/src/content/blog/anatomy-of-a-developer-targeted-supply-chain-attack.mdx:stripe-access-token:225Pięć pól, które mają znaczenie:
| Pole | Co Ci mówi |
|---|---|
| RuleID | Która reguła detekcji odpaliła (stripe-access-token, aws-access-token, generic-api-key, private-key itd.). Pełny domyślny zestaw reguł leży w config/gitleaks.toml w repozytorium gitleaks — każda reguła ze swoim regexem, opisem i wszelkimi filtrami słów kluczowych. |
| File + Line | Gdzie jest dopasowanie. |
| Commit | Który commit je wprowadził — nie musi być ten najnowszy. gitleaks znajduje je tam, gdzie po raz pierwszy pojawia się w historii. |
| Entropy | Entropia Shannona dopasowanego łańcucha, w bitach na znak. Wyżej = wygląda bardziej losowo, co zwykle znaczy, że bardziej prawdopodobnie jest prawdziwym sekretem. Reguły dla ogólnych kluczy API używają entropii jako głównego sygnału; reguły specyficzne dla dostawcy (Stripe, AWS) dopasowują prefiks i jej nie potrzebują. |
| Fingerprint | Stabilny identyfikator, którym stłumisz to znalezisko, jeśli okaże się dopuszczalne. Więcej o tym niżej. |
Co entropia właściwie mierzy
Entropia częstości znaków używana w skanowaniu wynosi −Σ p(c) log₂ p(c). Maksimum to log₂(N) dla N równie częstych symboli. Pomija kolejność znaków, więc przewidywalna sekwencja może mieć wysoki wynik; nie dowodzi losowości kryptograficznej.
Entropia to heurystyka używana wraz ze wzorcami i kontekstem. Teoretyczny limit wynosi 4 bity na znak dla zapisu szesnastkowego, około 5,95 dla alfabetu 62 znaków i 6 dla 64 znaków Base64. Krótkie próbki często wypadają niżej.
Wynik 4,175736 to jedna przesłanka, nie dowód aktywnego klucza. Przed decyzją sprawdź regułę i pochodzenie poświadczenia.
Triaż znalezisk
Gdy naprawdę uruchomisz gitleaks na prawdziwym repozytorium, dostaniesz znaleziska trzech kategorii — a ta sama reakcja nie pasuje do wszystkich trzech:
- Rzeczywiste poświadczenie: unieważnij lub obróć je, zbadaj ekspozycję i usuń z aktywnych plików. Przepisanie historii może ograniczyć dalsze ujawnianie, ale nie unieważnia klucza.
- Celowy przykład: przed wyciszeniem potwierdź, że to niesekretny placeholder albo zatwierdzona, unieważniona próbka. Cytowanie w artykule o bezpieczeństwie nie dowodzi nieszkodliwości.
- Fałszywy alarm: zapisz, dlaczego dopasowanie nie jest sekretem, i wycisz tę konkretną pozycję.
Dla kategorii 2 i 3 lekarstwem jest plik .gitleaksignore w korzeniu repozytorium, wyliczający identyfikatory — pole Fingerprint z tabeli powyżej — znalezisk, które przejrzałeś i zatwierdziłeś:
# Zamierzone: sekrety cytowane jako dowód w analizie ataku na łańcuch dostaw
49e4ca23a5ee6d1ef6b1a566a580a4086fbb84aa:blog/src/content/blog/anatomy-of-a-developer-targeted-supply-chain-attack.mdx:stripe-access-token:225
49e4ca23a5ee6d1ef6b1a566a580a4086fbb84aa:blog/src/content/blog/anatomy-of-a-developer-targeted-supply-chain-attack.mdx:generic-api-key:193gitleaks będzie pomijać dokładnie te znaleziska przy kolejnych skanach. Komentuj hojnie — przyszły Ty musi wiedzieć, czy każdy wpis został zatwierdzony, bo jest zamierzony, czy bo jest fałszywym alarmem, a komentarz to jedyny trwały zapis tej decyzji.
Zatrzymaj następny wyciek w momencie commita
Po sprawdzeniu historii i udokumentowaniu zaakceptowanych wyjątków dodaj gitleaks do:
- CI: skanuj commity przed scaleniem i publikacją.
- Hooki pre-commit: sprawdzaj przygotowane zmiany przed utworzeniem commita. Kontrole ograniczają przypadkowe wycieki, lecz mogą pomijać nieobsługiwane wzorce lub zostać ominięte.
Filtrowanie na brzegu z WAF-em
Web Application Firewall sprawdza żądania HTTP(S) według zestawu reguł, zanim dotrą do aplikacji. Może je przepuszczać, rejestrować, blokować lub wymagać dodatkowej weryfikacji. WAF pomaga w:
- Wyłapywania oczywistych ładunków dla klas ataków: wstrzyknięcie SQL, XSS, lokalne/zdalne włączanie plików, wstrzyknięcie komend, przechodzenie po ścieżkach.
- Blokowania znanych złych ścieżek (
/wp-admin/,.git/config,.env). - Ograniczania tempa, blokowania po reputacji IP, filtrowania geograficznego.
- Kupowania czasu, gdy w zależności, której nie możesz dziś podnieść, wychodzi CVE.
Nie jest użyteczny przy zepsutej logice biznesowej, zepsutej autoryzacji albo złym projekcie sesji. To środek kompensujący, nie lekarstwo.
WAF zarządzany i samodzielny mogą różnić się silnikiem, regułami, limitami i funkcjami operacyjnymi. Popularny własny zestaw to ModSecurity z OWASP Core Rule Set. CRS łączy dopasowania przez punktację anomalii; produkty zarządzane mogą używać reguł pochodnych i własnych detektorów.
Zarządzany: Cloud Armor
Zarządzany WAF ogranicza utrzymywaną infrastrukturę, lecz nadal wymaga integracji, strojenia i analizy fałszywych alarmów. Wybieraj według punktu wejścia ruchu i potrzebnych kontroli.
Natywną opcją GCP jest Google Cloud Armor. Przyczepia się do load balancera HTTP(S) w GCP, a jego prekonfigurowane grupy reguł (sqli-v33-stable, xss-v33-stable, lfi-v33-stable, rce-v33-stable itd.) wywodzą się wprost z OWASP CRS — tego samego zestawu reguł, który zainstalowałbyś ręcznie z ModSecurity.
Cloud Armor można konfigurować przez konsolę GCP, CLI gcloud, REST API albo — co pokażemy poniżej — deklaratywnie w Terraformie. Model jest ten sam niezależnie od interfejsu: polityka bezpieczeństwa Cloud Armor to lista reguł z warunkami dopasowania i akcjami (allow, deny(403), rate_based_ban). Minimalna polityka włączająca prekonfigurowane grupy reguł CRS i sensowną akcję domyślną wygląda tak:
resource "google_compute_security_policy" "app" {
name = "app-waf"
rule {
action = "deny(403)"
preview = true
priority = 1000
match {
expr { expression = "evaluatePreconfiguredWaf('sqli-v33-stable', {'sensitivity': 2})" }
}
description = "Block SQL injection"
}
rule {
action = "deny(403)"
preview = true
priority = 1001
match {
expr { expression = "evaluatePreconfiguredWaf('xss-v33-stable', {'sensitivity': 2})" }
}
description = "Block XSS"
}
rule {
action = "allow"
priority = 2147483647
match {
versioned_expr = "SRC_IPS_V1"
config {
src_ip_ranges = ["*"]
}
}
description = "Default allow"
}
}Tryb podglądu ocenia regułę bez blokowania. Skonfiguruj logowanie i próbkowanie, a przed włączeniem blokady sprawdź reprezentatywny ruch. Cichy próbkowany log nie dowodzi braku fałszywych alarmów.
Reguły własne Cloud Armor korzystają z podzbioru CEL, więc reguły ModSecurity SecRule wymagają przepisania. Możesz wybrać jedną z wersji CRS obsługiwanych przez Google, ale nie możesz załadować dowolnego wydania projektu. Uwzględnij opłaty za polityki i żądania oraz koszty load balancera.
Inne opcje to AWS WAF, Azure WAF i Cloudflare WAF. Różnią się miejscem wdrożenia, regułami i trybami podglądu lub logowania.
Samodzielnie: ModSecurity + NGINX
Ścieżka samodzielna jest właściwym wyborem, gdy chcesz pełnej kontroli nad regułami własnymi, nie jesteś w chmurze z dobrą ofertą zarządzaną, koszt na żądanie ma znaczenie przy Twoich wolumenach albo ograniczenia zgodności czynią urządzenie, które prowadzisz sam, łatwiejszym do uzasadnienia niż usługę dostawcy.
Konektor NGINX jest ładowany jako moduł dynamiczny i łączy NGINX z libmodsecurity, które ocenia skonfigurowane reguły. Architektura wygląda tak:
Internet → NGINX + ModSecurity → aplikacja w górę strumieniaOto jak ułożone są te trzy części:
- NGINX to odwrotne proxy. Terminuje TLS, przyjmuje wchodzące żądania HTTP i — gdy nic ich nie blokuje — proxuje je do aplikacji w górę strumienia na prywatnym porcie.
- libmodsecurity to silnik wyliczania reguł. To biblioteka w C++, odrębna od samego NGINX-a, bez własnego kodu sieciowego — po prostu bierze żądanie na wejściu i zwraca werdykt.
- Konektor ModSecurity dla NGINX-a to moduł dynamiczny (plik
.so), który spina te dwa. Wczepia się w potok obsługi żądań NGINX-a i dla każdego wchodzącego żądania przekazuje URL, nagłówki i ciało do libmodsecurity na wyliczenie.
Wszystkie trzy części działają wewnątrz tego samego procesu NGINX. Mechanizmem jest ładowacz modułów dynamicznych NGINX-a — i konektor, i libmodsecurity kończą wczytane do każdego workera NGINX-a przy starcie, bez odrębnego demona ModSecurity, bez IPC, bez gniazda między nimi.
Konektor wywołuje libmodsecurity wewnątrz procesu workera NGINX. Unika dodatkowego połączenia sieciowego, ale ocena reguł nadal wymaga obliczeń. Zbuduj konektor dla używanej wersji NGINX i konfiguracji modułów.
Dla każdego żądania NGINX przekazuje URL, nagłówki i ciało do libmodsecurity (przez konektor). libmodsecurity przepuszcza je przez wczytane reguły — OWASP CRS plus wszelkie własne — kumuluje punktację anomalii i zwraca akcję: allow, log albo deny. Jeśli werdykt to deny, NGINX zwraca skonfigurowaną odpowiedź błędu (zwykle 403) i nigdy nie przekazuje w górę strumienia. W przeciwnym razie żądanie idzie normalnie.
Gdy WAF jest na miejscu, upewnij się, że wszystko to jest prawdą:
- Ogranicz dostęp do aplikacji tak, aby żądania musiały przejść przez WAF. Publicznie dostępny serwer źródłowy pozwala go ominąć.
- TLS terminuje się na WAF-ie. ModSecurity nie może inspekcjonować tego, czego nie może odszyfrować.
- WAF jest teraz pojedynczym punktem awarii — uruchom co najmniej dwie instancje za LB, jeśli dostępność ma znaczenie.
- Wolumen dziennika audytowego skoczy. Zaplanuj magazyn.
Przykładowa instalacja na Debianie/Ubuntu (skrótowo):
# libmodsecurity
git clone --depth 1 -b v3/master https://github.com/owasp-modsecurity/ModSecurity
cd ModSecurity && git submodule init && git submodule update
./build.sh && ./configure && make -j$(nproc) && make install
# moduł-konektor dla NGINX-a (musi odpowiadać Twojej wersji NGINX-a)
git clone --depth 1 https://github.com/owasp-modsecurity/ModSecurity-nginx
cd nginx-${NGINX_VERSION}
./configure --with-compat --add-dynamic-module=../ModSecurity-nginx
make modules && cp objs/ngx_http_modsecurity_module.so /etc/nginx/modules/
# OWASP Core Rule Set
git clone --depth 1 https://github.com/coreruleset/coreruleset /etc/nginx/modsec/crs
cp /etc/nginx/modsec/crs/crs-setup.conf.example /etc/nginx/modsec/crs/crs-setup.confNastępnie w nginx.conf:
load_module modules/ngx_http_modsecurity_module.so;
http {
modsecurity on;
modsecurity_rules_file /etc/nginx/modsec/main.conf;
server {
listen 443 ssl;
server_name legacy-app.example.com;
ssl_certificate /etc/ssl/certs/app.crt;
ssl_certificate_key /etc/ssl/private/app.key;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}Wdrażaj najpierw w trybie tylko-detekcji. Ustaw SecRuleEngine DetectionOnly na co najmniej tydzień. Czytaj dziennik audytowy. Szukasz fałszywych alarmów (reguły CRS odpalające na legalnym ruchu — edytory, panele administracyjne, wysyłanie plików) i nieoczekiwanych prawdziwych trafień (ataki, które już Cię dotykają). CRS używa punktacji anomalii — reguły dodają wynik, a żądanie jest blokowane tylko wtedy, gdy suma przekroczy próg — co czyni dostrajanie łagodniejszym niż blokowanie per reguła.
Gdy znajdziesz fałszywy alarm, użyj najpierw SecRuleRemoveById zawężonego do konkretnego location, w drugiej kolejności obniż poziom paranoi na ścieżce, a wyłącz regułę globalnie tylko w ostateczności. Dopiero gdy dzienniki są dość ciche, by być sensowne, przełącz SecRuleEngine On.
Dla /api/report?format=X poniższa reguła fazy 1 odrzuca wartości format spoza dozwolonej listy w query stringu. Nie wymaga obecności parametru ani nie sprawdza go w treści żądania:
SecRule REQUEST_URI "@beginsWith /api/report" \
"id:1000001,phase:1,chain,deny,status:400,\
msg:'virtual patch: /api/report format allowlist'"
SecRule ARGS:format "!@rx ^(pdf|csv|json)$"Ochrona przed botami i CAPTCHA
Pozostałe warstwy tego zestawu ledwie dotykają klasy zagrożeń, która niemal na pewno dosięgnie publiczną aplikację odziedziczoną: oportunistyczne nadużycia botów na endpointach, które muszą być nieuwierzytelnione — spamowe rejestracje, ataki z użyciem wykradzionych danych logowania na Twoim formularzu logowania, masowe pobieranie danych, zautomatyzowane nadużycia kuponów, zalewy resetów hasła wywołujące maile na skalę.
Publiczne logowanie, rejestracja i reset hasła wymagają ochrony przed nadużyciami obok uwierzytelniania. Limity i sygnały botów pomagają, ale nie odróżniają idealnie rozproszonego ataku od poprawnego ruchu.
Poniższe opcje obejmują wyzwania w przeglądarce, punktację ryzyka żądań i wykrywanie anomalii ruchu. To powiązane, lecz odrębne funkcje.
Integracje przeglądarkowe tworzą tokeny wymagające walidacji na serwerze lub brzegu sieci. Detektory sieciowe używają innych sygnałów; część produktów łączy je także z JavaScriptem po stronie klienta.
Zaczniemy od najprostszego w ustawieniu — Cloudflare Turnstile — a potem spojrzymy na głębszą, natywną dla GCP kombinację reCAPTCHA Enterprise plus Cloud Armor Adaptive Protection dla zespołów, które potrzebują więcej.
Cloudflare Turnstile (najprostsza droga)
Cloudflare Turnstile oferuje wyzwania przeglądarkowe i token weryfikowany przez Siteverify API. Tryb zarządzany może wymagać interakcji; nie zawsze jest niewidoczny i nie udostępnia oceny ryzyka jak reCAPTCHA. Migracja z reCAPTCHA wymaga zmian klienta i serwera.
Turnstile można używać bez przenoszenia hostingu lub DNS do Cloudflare. Skonfiguruj zarówno widżet, jak i walidację serwerową według dokumentacji.
Turnstile przestaje wystarczać, gdy potrzebujesz drobniejszej kontroli — wyników per żądanie, na które możesz zareagować (a nie tylko przeszło/nie przeszło), egzekucji na load balancerze zamiast w kodzie aplikacji albo reguł subtelniejszych niż „wyzwanie zaliczone / niezaliczone”. To właśnie tę lukę zapełnia kombinacja reCAPTCHA Enterprise + Cloud Armor poniżej.
reCAPTCHA Enterprise (głębsza integracja z GCP)
reCAPTCHA może zwracać oceny ryzyka i ich przyczyny. Wynik to sygnał ryzyka, a nie skalibrowane prawdopodobieństwo, że użytkownik jest człowiekiem. Typy kluczy i wyzwania zależą od integracji.
Cloud Armor może oceniać obsługiwane tokeny reCAPTCHA w regułach bezpieczeństwa. Sprawdzaj poprawność tokenu obok wyniku; brakujące i błędne tokeny wymagają jawnej polityki.
rule {
action = "deny(403)"
priority = 500
match {
expr {
expression = "token.recaptcha_action_token.valid && token.recaptcha_action_token.score < 0.5"
}
}
description = "Block low-score bot traffic to sensitive endpoints"
}W tej integracji klient wysyła obsługiwany token, a Cloud Armor stosuje regułę przed backendem. Aplikacja nadal potrzebuje uwierzytelniania, autoryzacji i obsługi nadużyć.
Jest też tryb właściwego WAF-a w Cloud Armor zwany akcjami zarządzania botami (redirect, googleRecaptcha), który wystawia wyzwanie reCAPTCHA wprost na brzegu — użyteczne dla scenariusza „podejrzany skok ruchu, rzucamy wyzwanie wszystkim, aż opadnie”.
Tylko klasyfikator (bez integracji po stronie klienta)
Usługi brzegowe mogą wykrywać anomalie ruchu bez widżetu na każdym formularzu. To odrębna funkcja od weryfikowania wyzwania lub oceny każdego żądania pod kątem botów.
Cloud Armor Adaptive Protection skupia się na DDoS warstwy 7 i sugerowanych regułach obrony. Cloudflare Bot Management dostarcza sygnały botów z wielu metod detekcji. Zakresy częściowo się pokrywają, ale to nie równoważne klasyfikatory pojedynczych żądań.
Wyzwania utrudniają działanie zarówno automatom, jak i legalnym użytkownikom. Ich wartość zależy od endpointu, atakujących, dostępności i odsetka fałszywych alarmów. Nie gwarantują, że żądanie pochodzi od człowieka.
- Stosuj kontrole do działań podatnych na nadużycia, np. rejestracji, logowania i resetu hasła.
- Weryfikuj tokeny na serwerze i jawnie obsługuj ich brak lub niepoprawność.
- Łącz je z limitami i monitoringiem.
- Chroń administrację uwierzytelnianiem i autoryzacją; w razie potrzeby dodaj ograniczenia sieciowe.
Za brzegiem — skanowanie zależności z OSV-Scanner
Skanowanie zależności bada biblioteki dostarczane z aplikacją. Uzupełnia filtrowanie ruchu, wskazując znane podatne wersje wymagające oceny i ewentualnej aktualizacji.
Dlaczego OSV-Scanner
OSV-Scanner sprawdza wersje zależności w bazie OSV, która agreguje ostrzeżenia z wielu ekosystemów, w tym GitHub Security Advisories. Źródła i zakres pakietów różnią się między skanerami.
Czyta popularne pliki lock (package-lock.json, yarn.lock, Pipfile.lock itd.), rozwiązuje każdy pakiet w jego dokładnie przypiętej wersji i raportuje luki z identyfikatorami CVE, wagą i (gdzie OSV to ma) zakresem wersji, który je naprawia.
Uruchamiamy skan i czytamy wyjście
OSV-Scanner da się zainstalować przez Go, Homebrew, gotowym binarnym plikiem albo — tak samo jak gitleaks powyżej — uruchomić przez Dockera. Dla spójności pokażemy Dockera.
Właśnie uruchomiłem to na repozytorium, w którym żyje ten artykuł:
docker run --rm -v "$(pwd):/src" ghcr.io/google/osv-scanner:latest \
scan source --recursive /src--recursive przechodzi przez każdy katalog pod /src i znajduje pliki lock w zagnieżdżonych projektach (blog, kilka dem, serwer, eksperymenty szkicowe). Bez tego skaner inspekcjonuje tylko górny poziom — w porządku dla repozytorium jednoprojektowego, ale większość prawdziwych ma pliki lock rozsiane po kilku katalogach.
Podsumowanie na końcu przebiegu wygląda tak:
Total 35 packages affected by 59 known vulnerabilities (2 Critical, 17 High, 37 Medium, 3 Low, 0 Unknown) from 2 ecosystems.
59 vulnerabilities can be fixed.Zapisany skan zawiera m.in. poniższe wyniki. To obraz repozytorium i bazy ostrzeżeń z chwili skanowania, a nie opis bieżącego checkoutu.
| OSV URL | CVSS | Ekosystem | Pakiet | Wersja | Wersja naprawiona | Źródło |
|---|---|---|---|---|---|---|
| GHSA-xq3m-2v4x-88gg | 9.4 | npm | protobufjs | 7.5.4 | 7.5.5 | blog/…/transformers-js-demo/package-lock.json |
| GHSA-p9ff-h696-f583 | 8.2 | npm | vite | 7.3.1 | 7.3.2 | blog/package-lock.json |
| PYSEC-2025-40 | 7.5 | PyPI | transformers | 4.48.3 | 4.49.0 | blog/…/from-scratch/requirements.txt |
| GHSA-r5fr-rjxr-66jc | 8.1 | npm | lodash | 4.17.23 | 4.18.0 | server/package-lock.json |
OSV URL— prowadzi prosto do ostrzeżenia na osv.dev (identyfikator CVE, wektor ataku, zakres dotkniętych wersji, odnośniki).CVSS— wynik wagi na skali 0–10. 9+ to Critical, 7–8.9 to High, 4–6.9 to Medium.Ecosystem— z którego rejestru pakietów pochodzi zależność. Ta sama nazwa pakietu może istnieć w wielu ekosystemach i dostawać różne CVE.PackageiVersion— co jest obecnie przypięte w pliku lock.Fixed version— najniższa wersja, która rozwiązuje problem. Często podniesienie łatki; czasem minor albo major.Source— z którego pliku lock przyszło znalezisko. Krytyczne dla monorepozytoriów: ten sam pakiet może być przypięty w różnych wersjach w różnych podprojektach, co dokładnie widzimy dlavite,protobufjsipicomatchw rzeczywistym skanie.
Zauważ, że podsumowanie rozbija licznik na dwa sposoby: 59 znanych luk ogółem i 59 luk da się naprawić — czyli każda ma znany cel podniesienia. W tym skanie się pokrywają, co nie zawsze jest regułą.
Wersja z poprawką to kandydat do aktualizacji, nie dowód zgodności ani kompletności zmiany. Przeczytaj ostrzeżenie, sprawdź gałęzie wydań i zależności przechodnie, a potem przetestuj zmianę.
OSV-Scanner obsługuje też pliki blokad, SBOM i obrazy. Sprawdź dokumentację zainstalowanej wersji pod kątem składni i dostępu do kontenerów.
Co zrobić ze znaleziskami
Uruchom to raz na aplikacji odziedziczonej i niemal na pewno dostaniesz ścianę znalezisk — łatwo dziesiątki, czasem setki. Dla każdego znaleziska o tym, co zrobić, decydują dwa pytania: jak poważne to jest i czy jest dostępna naprawa.
Priorytetyzuj aktywnie wykorzystywane i dostępne z zewnątrz podatności, uwzględniając wagę, osiągalność kodu, zagrożone dane i środki zaradcze. Niski wynik nie uzasadnia automatycznego ignorowania, a wysoki nie wyznacza takiego samego terminu dla każdego systemu.
Wyniki bez dostępnej poprawki wymagają ograniczania ryzyka i dalszego śledzenia:
Jeśli nie ma użytecznej aktualizacji, rozważ wyłączenie funkcji, ograniczenie dostępu lub wymianę zależności. Reguła WAF może pomóc tymczasowo tylko wtedy, gdy atak przechodzi przez ruch, który WAF analizuje. Wyciszenia dokumentuj z właścicielem i datą przeglądu; nie usuwają podatności.
Alternatywy i kiedy którą wybrać
Inne opcje to Artifact Analysis dla obsługiwanych obrazów, Trivy dla różnych artefaktów i konfiguracji oraz Dependabot dla alertów i PR-ów aktualizacyjnych. Włącz potrzebne funkcje i sprawdź zakres ekosystemów; to nie zamienne skany tych samych danych.
Rozsądny minimalny zestaw: OSV-Scanner w CI (blokuje build na nowych znaleziskach wysokiej wagi) + Dependabot (ciągle otwiera PR-y podnoszące). Jeśli już wysyłasz kontenery, albo dodaj Trivy do skanowania obrazów, albo — jeśli pushujesz do rejestru chmurowego — opieraj się na wbudowanym skanerze rejestru (Artifact Analysis na GCP, ECR + Inspector na AWS), a nie prowadź kolejnego narzędzia.
Skanery to nie higiena łańcucha dostaw
Skanowanie znanych podatności nie jest pełną ochroną łańcucha dostaw. Niektóre źródła obejmują znane złośliwe pakiety, ale skanery nie gwarantują wykrycia nowego backdoora, przejętego konta opiekuna czy skryptu instalacji. Sprawdzaj zmiany zależności i ograniczaj dostęp podczas instalacji.
NPM Security Cheat Sheet od OWASP to użyteczna konkretna lista kontrolna do tego, jeśli Twój stos to Node.js — obejmuje --ignore-scripts, npm audit, pakiety w scope, wypatrywanie literówek i więcej. Vulnerable Dependency Management Cheat Sheet od OWASP pokrywa ten sam grunt niezależnie od języka. Oba dobrze łączą się z warstwą opartą na skanerach powyżej: skanery na znane-złe, higiena na nieznane-złe.
Co ten zestaw pokrywa i gdzie można pójść dalej
Jeśli wdrożysz trzy podstawowe warstwy plus skanowanie zależności, co właściwie sobie kupiłeś?
Co mogą ograniczyć te kontrole: ujawnione sekrety, wykorzystanie znanych podatności po ich załataniu, żądania pasujące do wzorców ataków i część automatycznych nadużyć. Zakres zależy od konfiguracji, ograniczeń detekcji i reakcji na wyniki.
Wciąż pominięte:
- Podatne wzorce wewnątrz Twojego własnego kodu. WAF blokuje ładunki w czasie żądania, ale nie pomaga Ci znaleźć ani naprawić leżącego pod tym podatnego kodu. SAST i DAST poniżej to sposób, by zacząć to robić.
- Wady logiki aplikacji — wszystko, co wymaga wiedzy, co aplikacja ma robić. IDOR (żądanie do
/orders/1234, gdy użytkownik powinien widzieć tylko1233), zepsute uwierzytelnianie albo zarządzanie sesją, brakujące lub niespójne sprawdzenia autoryzacji, błędy logiki biznesowej w rodzaju pominięcia kroku płatności przez powtórne wysłanie żądania finalizacji koszyka. Żadne z tych nie wygląda złośliwie dla skanera. - Nowe podatności zero-day w aplikacji albo jej zależnościach, przed istnieniem sygnatur.
- Zdeterminowani przeciwnicy. Insiderzy nadużywający legalnego dostępu. Dobrze uposażeni operatorzy botów, którzy płacą usługom rozwiązywania CAPTCHA i rotują IP szybciej, niż zdążysz ich blokować.
Co dodać w następnej kolejności: SAST i DAST
Gdy trzy podstawowe warstwy i skanowanie zależności są na miejscu, naturalnym następnym krokiem jest analizowanie samego kodu, a nie tylko ruchu przezeń płynącego. Dwie komplementarne techniki:
- SAST analizuje kod bez uruchamiania. Narzędzia takie jak Semgrep i CodeQL wykrywają obsługiwane wzorce podatności, lecz wymagają odpowiednich reguł i przeglądu.
- DAST bada działającą aplikację. ZAP oferuje analizę pasywną i testy aktywne. Nawet skan bazowy odwiedza aplikację i generuje ruch; wybieraj autoryzowany cel i uwzględnij efekty uboczne tras. Aktywne testy uruchamiaj w izolacji z jednorazowymi danymi.
Gdy jest to dozwolone, używaj uwierzytelnionych sesji DAST, aby dotrzeć do chronionych tras. Łącz zaplanowane skany z przeglądem autoryzacji i logiki biznesowej, które automaty mogą przeoczyć.