Jak działa ta kontrola
Scanaris ponownie pobiera Twoją stronę główną z nagłówkiem Origin ze zmyślonej domeny, tak jak zrobiłaby przeglądarka, gdyby inna strona próbowała Cię wywołać, i patrzy, co odpowiada Twój serwer. Jeśli Access-Control-Allow-Origin zwraca ten sam origin, a dodatkowo Access-Control-Allow-Credentials ma wartość true, otwiera znalezisko o wysokiej wadze: Twój serwer odbija dowolny origin z poświadczeniami. Jeśli odpowiada wildcardem * razem z poświadczeniami, otwiera znalezisko o niskiej wadze: przeglądarki odrzucają tę kombinację, ale zdradza ona konfigurację zrobioną na ślepo. Testowany jest tylko skanowany URL; jeśli Twoje API żyje na innej ścieżce lub domenie, sprawdź je poleceniem poniżej.
Co atakujący z tym robi
Stawia stronę na dowolnej domenie z fetch do Twojego API z credentials: 'include'. Gdy jeden z Twoich użytkowników z otwartą sesją odwiedzi tę stronę, przeglądarka dołącza jego ciasteczka, Twój serwer odpowiada danymi użytkownika, a skoro polityka CORS na to pozwala, strona atakującego je odczytuje. Profil, zamówienia, wiadomości, cokolwiek zwraca API. Użytkownik nic nie widzi: dzieje się to w tle.
Dlaczego tak się dzieje
CORS istnieje po to, żeby przeglądarka domyślnie blokowała odczyty między domenami. Gdy wywołanie pada w trakcie developmentu (aplikacja na jednym porcie, API na drugim), szybkim rozwiązaniem podsuwanym przez tutoriale i narzędzia AI jest „zezwolić na wszystkie originy", a żeby działały ciasteczka, dochodzi „z poświadczeniami". Na produkcji oznacza to, że ochrona została wyłączona. Więcej w źle skonfigurowany CORS: cichy błąd, który wystawia Twoich użytkowników.
Jak to naprawić
- Jawna lista originów. Tylko domeny, które naprawdę wywołują Twoje API z przeglądarki. W Expressie:
cors({ origin: ['https://app.twojadomena.com'], credentials: true }). W Next.js w Route Handlerze porównajOriginze swoją listą, zanim go zwrócisz. W Nuxt przezrouteRulesi opcjęcorsalbo middleware serwerowy. - Nigdy nie odbijaj originu. Kopiowanie wartości
Origindo odpowiedzi „bo wtedy wszystko działa" to dokładnie ten błąd, który mierzy kontrola. - Jeśli nie potrzebujesz ciasteczek między domenami, usuń
Access-Control-Allow-Credentials. Bez poświadczeń*na publicznym API tylko do odczytu jest akceptowalny. - Dodaj Vary: Origin, gdy odpowiedź zależy od originu, żeby żaden cache nie podał jednej domenie odpowiedzi przeznaczonej dla innej.
- Ciasteczka z SameSite=Lax lub Strict jako druga bariera: nawet gdyby CORS zawiódł, przeglądarka nie wyśle ich z innej strony.
Sprawdź, czy naprawione
curl -sI -H "Origin: https://evil.example" https://twojadomena.com/api/me | grep -i "access-control"
Prawidłowo Access-Control-Allow-Origin nie pojawia się dla tego originu albo pojawia się z Twoją domeną, a nie z evil.example. Przetestuj też z własną domeną w Origin, żeby potwierdzić, że aplikacja nadal działa.
Często zadawane pytania
Moje API jest publiczne i bez logowania. Czy to problem?
Nie, jeśli nie ma ciasteczek ani nagłówków autoryzacji. Access-Control-Allow-Origin: * bez poświadczeń to poprawna konfiguracja dla otwartego API.
Mam kilka subdomen wywołujących API.
Wymień je wszystkie albo waliduj Origin względem ścisłego wzorca swojej domeny głównej. Nigdy nie waliduj przez „zawiera twojadomena.com": twojadomena.com.evil.example to spełnia.
A localhost do developmentu?
Dodaj go tylko w środowisku deweloperskim, przez zmienną środowiskową. http://localhost:3000 na liście produkcyjnej to origin, którego może użyć każdy program na komputerze użytkownika.