# Publiczny katalog .git: niedoceniany wyciek danych

> Czy Państwa katalog .git jest publiczny? Jak to sprawdzić, zablokować dostęp, zmienić wdrażanie i potraktować dane dostępowe z historii repozytorium.

Źródło: https://phpsos.de/pl/blog/git-ordner-oeffentlich/  
Stan: 25.10.2026  
Dostawca: PHP SOS, Pomoc awaryjna PHP i bezpieczeństwo serwerów. Natychmiastowa pomoc przez WhatsApp: https://wa.me/491736494914?text=Dzie%C5%84%20dobry%2C%20PHP%20SOS%2C%20potrzebujemy%20pomocy%20z%20naszym%20serwerem%20PHP.%20Firma%3A%20%E2%80%A6%20Strona%20internetowa%3A%20%E2%80%A6

**Krótko:** Publiczny katalog .git powstaje, gdy strona jest wdrażana za pomocą `git clone` lub `git pull` bezpośrednio w webroot, a serwer WWW nie blokuje ukrytych katalogów. Wtedy można pobrać cały kod źródłowy wraz z historią wersji, łącznie z wcześniej zatwierdzonymi danymi dostępowymi. Sprawdź swoje domeny prostym wywołaniem, natychmiast zablokuj dostęp, przestaw wdrażanie na paczki bez `.git` i wymień dane dostępowe z historii.

## Kod źródłowy do zabrania

Git to standardowe narzędzie do kontroli wersji i dla małych zespołów naturalne jest użycie go także do wdrażania: połączyć się z serwerem, `git pull`, gotowe. Działa to niezawodnie i szybko. Ma jednak skutek uboczny, którego często nikt nie zauważa.

W katalogu projektu leży ukryty katalog `.git`. Zawiera nie tylko aktualny stan, ale każdy plik w każdej wersji, jaka kiedykolwiek została zatwierdzona, a do tego komunikaty commitów, imiona i adresy e-mail programistów oraz odniesienia do serwerów. Jeśli ten katalog leży w webroot, a serwer WWW go wydaje, każdy może go pobrać.

Dla atakujących to prezent. Dzięki kodowi źródłowemu można celowo szukać słabych punktów, zamiast zgadywać je z zewnątrz. A w historii często znajdują się rzeczy, które dawno wydawały się usunięte: hasło do bazy danych z początków projektu, klucz API, plik testowy z danymi klientów.

## Czy Państwa katalog .git jest publiczny? Jak to sprawdzić

Kontrola trwa sekundy i niczego nie zmienia. Wywołaj dla każdej domeny i subdomeny plik, który istnieje w każdym repozytorium Git:

```bash
# Oczekiwane: 403 lub 404
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.git/HEAD
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.git/config
# Na serwerze: czy poniżej webroot istnieją katalogi .git?
find /var/www /srv/www -maxdepth 4 -type d -name ".git" 2>/dev/null
```

Status 200 oznacza: katalog jest dostępny. Zwróć uwagę także na podkatalogi. Czasem repozytorium nie leży w samym webroot, lecz w katalogu wtyczki lub motywu, który jest utrzymywany osobno przez Git.

Sprawdź ponadto środowiska stagingowe i testowe. Są aktualizowane przez Git częściej niż produkcja i często są dostępne pod łatwymi do odgadnięcia subdomenami.

## Natychmiast: zablokować dostęp

Dopóki wdrażanie nie zostanie zmienione, reguła w serwerze WWW blokuje dostęp do katalogów kontroli wersji. Ogólna blokada ukrytych plików, opisana w artykule [Prawidłowa ochrona danych dostępowych i plików .env](https://phpsos.de/pl/blog/env-dateien-schuetzen/), obejmuje to również. Kto chce celowo zablokować tylko kontrolę wersji, stosuje węższą regułę:

```nginx
location ~ /\.(git|svn|hg)(/|$) {
    return 404;
}
```

```apache
RedirectMatch 404 /\.(git|svn|hg)(/|$)
```

Następnie powtórz powyższą kontrolę, i to rzeczywistym wywołaniem z zewnątrz: udany test konfiguracji mówi tylko, że składnia się zgadza, a nie że reguła działa przed innymi regułami dla plików statycznych. W panelach takich jak Plesk czy cPanel wpisz regułę w przewidziane do tego dodatkowe dyrektywy, aby nie zginęła przy następnym generowaniu konfiguracji.

> **Działać natychmiast:**
> Jeśli katalog był dostępny, traktuj wszystkie dane dostępowe, które kiedykolwiek znajdowały się w repozytorium, jako znane. Sama blokada nie wystarcza, wartości muszą zostać wymienione.

## Trwale: wdrażać bez .git w webroot

Blokada jest zabezpieczeniem, a nie rozwiązaniem. Trwale kontrola wersji nie należy na serwer produkcyjny. Sprawdzone drogi, zależnie od Państwa środowiska:

| Metoda | Jak działa | Odpowiednia dla |
|---|---|---|
| Paczka budowana w CI | Pipeline buduje archiwum bez `.git`, serwer rozpakowuje je do nowego katalogu wydania | Zespoły z CI/CD |
| `git archive` | tworzy archiwum danego stanu bez danych wersji | małe projekty bez pipeline |
| `rsync` z wykluczeniami | przesyła tylko niezbędne pliki | klasyczne serwery |
| Obraz kontenera | Kod jest kopiowany do obrazu podczas budowy, `.git` wykluczony przez `.dockerignore` | działanie w kontenerach |

Katalog wydania dla każdej wersji z dowiązaniem symbolicznym do bieżącego stanu ma dodatkową zaletę: w razie problemów można natychmiast się cofnąć. Dla konfiguracji kontenerowych artykuł [CI/CD: automatyczna przebudowa obrazów PHP](https://phpsos.de/pl/blog/php-images-in-ci-neu-bauen/) opisuje, jak sprawić, aby buildy były powtarzalne. Tam należy też sprawdzić, czy `.git` nie trafia do obrazu.

```bash
# Przykład: utworzyć paczkę danego stanu bez danych wersji
git archive --format=tar.gz -o release.tar.gz HEAD
```

## Inne pliki projektu, które nie należą do webroot

Katalog `.git` to najbardziej znany przykład, ale nie jedyny. Kto wdraża całe katalogi projektu, przenosi do webroot kolejne pliki, które nie mają tam czego szukać:

- Katalogi środowisk programistycznych, takie jak `.idea` lub `.vscode`, w których rozszerzenia do przesyłania plików czasem zapisują adresy serwerów i dane dostępowe.
- `composer.json` i `composer.lock`, które zdradzają dokładne wersje wszystkich bibliotek i ułatwiają tym samym szukanie znanych luk.
- Konfiguracje testów, narzędzi budowania i pipeline, które ujawniają wewnętrzne nazwy hostów i procesy.
- Pozostałości systemów operacyjnych, takie jak `.DS_Store`, zawierające listy plików całych katalogów.

Rozwiązanie jest takie samo jak w przypadku katalogu `.git`: wydawać tylko to, co musi być publiczne, najlepiej przez osobny podkatalog jako webroot. Kto i tak przestawia wdrażanie na paczki, od razu ustala listę wykluczonych plików i sprawdza ją przy każdym nowym narzędziu w projekcie.

## Gdy katalog był otwarty: sprawdzić historię i logi

Jeśli okaże się, że katalog `.git` był dostępny, postępuj w tej kolejności:

1. **Zablokować dostęp** i powtórzyć kontrolę.
2. **Przeszukać historię**, jakie sekrety kiedykolwiek zostały zatwierdzone: pliki konfiguracyjne, `.env`, klucze, zrzuty baz danych.
3. **Wymienić dane dostępowe**, i to wszystkie, które znaleziono w kroku 2, nawet jeśli dziś nie ma ich już w kodzie.
4. **Przeanalizować logi dostępu**, czy pliki pod `/.git/` były pobierane ze statusem 200 i z jakich adresów. Jak to zrobić, pokazuje artykuł [Analiza logów serwera WWW po ataku](https://phpsos.de/pl/ratgeber/logfiles-auswerten/).
5. **Celowo sprawdzić kod źródłowy**, ponieważ atakujący znają go teraz. Znane słabości należy usunąć w pierwszej kolejności.
6. **Wyjaśnić kwestię ochrony danych**, jeśli w historii znajdowały się dane osobowe, na przykład eksporty testowe. Ocenę przejmuje Państwa inspektor ochrony danych.

Narzędzia do wyszukiwania sekretów w repozytoriach powinny następnie trwale trafić do pipeline. OWASP wyraźnie zaleca takie kontrole, jako hook przed zatwierdzeniem i w CI.

## Jak konkretnie pomaga PHP SOS?

- Sprawdzamy wszystkie Państwa domeny i subdomeny pod kątem dostępnych katalogów kontroli wersji.
- Natychmiast blokujemy dostęp i przestawiamy wdrażanie na paczki bez danych wersji.
- Przeszukujemy historię pod kątem sekretów i wspieramy wymianę dotkniętych dostępów.
- Analizujemy logi dostępu i dokumentujemy, czy i kiedy dane były pobierane.

Te środki są częścią naszego [utwardzania serwerów PHP](https://phpsos.de/pl/leistungen/server-haertung/).


## Częste pytania

**Jak powstaje publiczny katalog .git?**  
Zwykle przez wdrożenie za pomocą git clone lub git pull bezpośrednio w webroot. Katalog .git z całą historią wersji leży wtedy obok index.php, a bez blokady serwer WWW wydaje jego pliki.

**Czy wystarczy usunąć katalog .git?**  
Na przyszłość tak, na przeszłość nie. Jeśli katalog był dostępny, jego zawartość mogła już zostać skopiowana. Dane dostępowe, które kiedykolwiek znajdowały się w repozytorium, należy więc wymienić.

**Czy pomaga późniejsze usunięcie danych dostępowych z historii Git?**  
Zapobiega to temu, aby nowe kopie je zawierały. Kto już pobrał repozytorium, nadal ma stare stany. Decydująca jest więc wymiana danych dostępowych, a nie tylko przepisanie historii.

**Czy dotyczy to także innych systemów kontroli wersji?**  
Tak. Także katalogi takie jak .svn lub .hg zawierają dane projektu i nigdy nie powinny być dostępne w webroot. Ogólna blokada plików i katalogów z kropką na początku obejmuje wszystkie te przypadki.

## Źródła

- [OWASP Secrets Management Cheat Sheet (ściągawka o zarządzaniu sekretami)](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html)
- [Dokumentacja Nginx](https://nginx.org/en/docs/)
- [Serwer HTTP Apache: dokumentacja](https://httpd.apache.org/docs/)
