Jak działa ta kontrola
Scanaris żąda dwóch plików w roocie Twojej domeny: /package.json, manifestu projektu Node, i /composer.json, manifestu projektu PHP. Dla każdego potwierdza ustalenie tylko wtedy, gdy odpowiada 200, treść nie jest HTML-em, jest poprawnym JSON-em i zawiera klucze właściwe dla danego manifestu: dependencies lub devDependencies w pierwszym, require lub require-dev w drugim. Dzięki temu nie oznacza aplikacji jednostronicowej, która zwraca swój HTML dla dowolnej ścieżki, ani przypadkowego JSON-a, który akurat tam mieszka. Każdy znaleziony plik otwiera ustalenie o niskiej wadze.
Dlaczego to ważne
Te pliki nie zawierają sekretów, ale zawierają coś prawie równie użytecznego dla atakującego: dokładną listę bibliotek, których używasz, wraz z wersjami. Z nią nie musi niczego zgadywać: zestawia Twoją listę z bazą znanych podatności i wie, który exploit wypróbować i przeciwko czemu. Ujawniają też wewnętrzną nazwę projektu, skrypty builda i wdrożenia, czasem adres prywatnego repozytorium i nazwy wewnętrznych pakietów Twojej organizacji, które są punktem wyjścia ataków dependency confusion. To niska waga, bo to informacja, nie dostęp; ale informacja, którą oddajesz bez powodu.
Dlaczego tak się dzieje
Bo serwer WWW serwuje cały katalog projektu zamiast katalogu wyjściowego. Poprawnie wdrożone Vite, Nuxt czy Next.js publikują tylko dist/, .output/public/ lub .next/static/, a tam nie ma package.json. Pojawia się, gdy całe repozytorium wgrywa się przez FTP do public_html, gdy katalog główny hostingu statycznego wskazuje na root projektu, albo w projektach PHP, gdzie composer.json leży w tym samym katalogu co index.php, co jest typowe w WordPressie z Composerem i w instalacjach robionych ręcznie.
Jak to naprawić
- Serwuj tylko katalog publiczny. Na Vercel i Netlify sprawdź „output directory" lub „publish directory" projektu; musi to być katalog builda, nie
.. W nginx i ApacherootlubDocumentRootwskazuje napublic/lubdist/. - W PHP przenieś
composer.json,composer.lockivendor/o poziom wyżej nad katalog publiczny, jeśli framework na to pozwala (Laravel i Symfony już tak robią). Jeśli nie możesz ich przenieść, zablokuj je:
location ~* /(package|composer)(-lock)?\.json$ { return 404; }
location ~* /(yarn|pnpm-lock)\.(lock|yaml)$ { return 404; }
- W Apache
<FilesMatch "^(package|composer)(-lock)?\.json$"> Require all denied </FilesMatch>w konfiguracji lub w.htaccess. - Sprawdź, co jeszcze zostało wgrane. Tam, gdzie jest publiczny
package.json, zwykle obok leży.env,.git/albocomposer.lock; kontrola wrażliwe pliki szuka tych poważnych.
Sprawdź, czy naprawione
for p in package.json composer.json package-lock.json composer.lock yarn.lock; do
printf "%-20s " "$p"; curl -s -o /dev/null -w "%{http_code} %{content_type}\n" "https://twojadomena.pl/$p"
done
Oczekiwane: 404 lub 403. 200 z text/html to ogólny HTML aplikacji jednostronicowej i nie jest problemem; 200 z application/json to prawdziwy plik.
Często zadawane pytania
Moje repozytorium i tak jest publiczne na GitHubie.
W takim razie manifest już jest publiczny i to ustalenie nie dodaje nowej ekspozycji; możesz je uznać za zaakceptowane. Mimo to poprawienie roota serwera zapobiega przypadkowemu opublikowaniu następnego pliku, który trafi do katalogu projektu.
A pliki lock?
Ta kontrola patrzy na dwa manifesty, ale package-lock.json, yarn.lock i composer.lock są gorsze: wymieniają wszystkie zależności przechodnie z dokładną wersją. Jeśli manifest jest wystawiony, plik lock prawie na pewno też; powyższa reguła blokująca je obejmuje.
Jeśli nie serwuję manifestu, nikt nie dowie się, jakich wersji używam?
Mogą to wywnioskować innymi, wolniejszymi drogami: nagłówki, ścieżki bundle'i, zachowanie. To, co przestarzałe biblioteki wykrywa w Twoim JavaScripcie, widzi na przykład każdy. Ukrycie manifestu zabiera skrót; aktualizacja zależności zabiera problem.