Dozwolone ścieżki dowiązań symbolicznych
Domyślnie OxPHP odrzuca każde żądanie, które rozwiązuje się do ścieżki poza kanonicznym DOCUMENT_ROOT. Dowiązanie symboliczne wewnątrz DOCUMENT_ROOT wskazujące na zewnętrzny katalog zwraca 404, a rozwiązywanie ścieżki zapisuje w logach Blocked request: resolved path escapes document root.
To właściwe ustawienie domyślne: zatrzymuje przechodzenie po katalogach (directory traversal), ataki TOCTOU z podmianą dowiązania symbolicznego oraz przypadkowe ujawnienie plików konfiguracyjnych lub sekretów leżących o poziom wyżej. Blokuje jednak także uzasadnione wzorce, które frameworki stosują od lat: php artisan storage:link w Laravelu, pakiety zasobów Symfony, współdzielone wolumeny przesyłanych plików montowane w wielu kontenerach.
SYMLINK_ALLOW_PATHS to jawna zgoda: wskazujesz ścieżki w systemie plików, do których dowiązania symboliczne pod DOCUMENT_ROOT mogą się rozwiązywać. Wszystko, czego nie ma na liście, zachowuje ścisłe zachowanie z odpowiedzią 404.
Konfiguracja
# Absolute paths, comma-separated
SYMLINK_ALLOW_PATHS=/var/www/storage,/opt/shared/assets
# Relative paths resolve against DOCUMENT_ROOT
SYMLINK_ALLOW_PATHS=../storage,../shared/uploads
# Mixed
SYMLINK_ALLOW_PATHS=/opt/shared/cdn,../storage/app/publicGdy zmienna nie jest ustawiona (ustawienie domyślne), żadne dowiązanie symboliczne nie może opuścić DOCUMENT_ROOT.
Przykład dla Laravela
DOCUMENT_ROOT=/app/public
SYMLINK_ALLOW_PATHS=../storage/app/publicWtedy php artisan storage:link tworzy public/storage -> ../storage/app/public wewnątrz projektu. Adresy URL wskazujące na /storage/<file> rozwiązują się przez dowiązanie symboliczne do /app/storage/app/public/<file>, co kanonizuje się do ścieżki, którą lista dozwolonych autoryzuje. Bez żadnej zmiany w kodzie aplikacji.
Jak to działa
Podczas uruchamiania każdy wpis jest rozwiązywany:
- Wpisy bezwzględne — sprawdzane względem listy blokowania (patrz niżej), następnie przepuszczane przez
realpath(3)(czylistd::fs::canonicalize). Jeślirealpathzawiedzie (cel nie istnieje), serwer odmawia uruchomienia. - Wpisy względne — łączone z kanonicznym
DOCUMENT_ROOT, a następnie poddawane działaniurealpath.
Powstałe kanoniczne ścieżki są zapisywane jako lista dozwolonych. Duplikaty są po cichu usuwane.
W momencie żądania warstwa routingu kanonizuje rozwiązaną ścieżkę pliku i weryfikuje, czy spełnia jeden z warunków:
- leży wewnątrz
DOCUMENT_ROOT, albo - jest dokładnie równa jednemu z wpisów listy dozwolonych (cele będące plikami), albo
- zaczyna się od jednego z wpisów listy dozwolonych, po którym następuje
/(cele będące katalogami).
Ta sama kontrola uruchamiana jest po raz drugi jako zabezpieczenie przed TOCTOU wewnątrz ścieżki serwowania plików statycznych, po pamięci podręcznej tras, a przed jakimkolwiek wywołaniem systemowym odczytu.
Lista blokowania
Niewielki zbiór ścieżek nigdy nie może pojawić się w SYMLINK_ALLOW_PATHS; literówki i nieporozumienia w przeciwnym razie drastycznie poszerzyłyby powierzchnię ataku. Serwer odmawia uruchomienia, jeśli którykolwiek wpis rozwiązuje się do ścieżki z listy blokowania.
Zabronione jako dokładne dopasowanie:
/ /etc /proc /sys /dev /var /home /tmp /root /usr /srvZabronione jako prefiks (wpis leży pod jednym z tych katalogów):
/etc /proc /sys /dev /tmp /root /usr/var, /home i /srv są dozwolone wyłącznie jako dokładne dopasowanie: samo /srv jest odrzucane, ale /srv/myapp/storage jest dozwolone, tak samo jak dozwolone są /var/www/storage oraz /home/<any>/.... Wpisy są sprawdzane dwukrotnie: raz względem surowej ścieżki podanej przez administratora (tak aby ścieżka w stylu macOS /etc -> /private/etc nie mogła przemycić zablokowanej ścieżki przez realpath), raz względem postaci kanonicznej (obrona w głąb przeciwko ucieczkom celu dowiązania symbolicznego).
Sama lista blokowania jest zaszyta w kodzie; nie ma zmiennej środowiskowej, która by ją rozszerzała. Ustawienie domyślne to konserwatywne minimum wychwytujące błędy na poziomie literówek; administratorzy potrzebujący surowszych zasad powinni nakładać je z zewnątrz (uprawnienia systemu plików, ograniczenia montowania w kontenerach, profile AppArmor/SELinux).
Tryby awaryjne
| Błąd konfiguracji | Wynik |
|---|---|
| Cel wpisu nie istnieje na dysku | Serwer odmawia uruchomienia, błąd wskazuje wpis oraz canonicalize |
| Wpis pasuje do listy blokowania (surowy lub kanoniczny) | Serwer odmawia uruchomienia, błąd wskazuje wpis oraz regułę listy blokowania |
| Pusta zmienna środowiskowa lub zawierająca tylko białe znaki | Traktowana jako nieustawiona — ścisłe zachowanie domyślne |
| Zduplikowane wpisy | Po cichu usuwane po kanonizacji |
| Podczas uruchamiania nie istnieje jeszcze żadne dowiązanie symboliczne | Lista dozwolonych jest zarejestrowana, ale bezczynna do momentu pojawienia się dowiązania symbolicznego; żadna kontrola przy uruchamianiu nie wymaga dowiązania |
Uwagi dotyczące bezpieczeństwa
- Lista dozwolonych działa na zasadzie jawnej zgody — bezpieczne ustawienie domyślne „bez ucieczek" jest zachowane, gdy zmienna nie jest ustawiona
- Wpisy są kanonizowane podczas uruchamiania, więc
..oraz pośrednie dowiązania symboliczne w ścieżce wpisu są zwijane przed zapisaniem - Kanonizacja w czasie działania zamyka okno TOCTOU związane z podmianą dowiązania symbolicznego — zweryfikowana ścieżka to ta sama ścieżka, która zostaje odczytana
- Cele będące plikami dopasowywane są dokładnie; cele będące katalogami dopasowywane są po prefiksie katalogu. Umieszczenie na liście pliku
/etc/passwdi tak zostałoby odrzucone przez listę blokowania, ale bardziej ogólnie: umieszczenie na liście pojedynczego pliku/opt/shared/license.keynie daje niejawnie dostępu do plików sąsiednich - Wyniki walidacji ścieżek są buforowane per żądany adres URL (jeden
realpathna unikalny adres URL do momentu usunięcia z pamięci podręcznej), więc koszt działania jest amortyzowany
Zobacz także
- Zabronione ścieżki PHP — blokowanie wykonywania PHP pod określonymi wzorcami URI (glob); ortogonalne wobec polityki dowiązań symbolicznych
- Blokowanie ścieżek z kropką — odrzuca przechodzenie w stylu
.well-knownoraz wycieki plików ukrytych - Zaufane proxy — osobna granica zaufania dla nagłówków
X-Forwarded-* - Dokumentacja konfiguracji — wszystkie zmienne środowiskowe