Nagłówki jako worki
Frameworki logowania HTTP traktują nagłówki żądań jako worek par klucz-wartość. API logowania udostępnia cały worek. Operatorzy włączają logowanie nagłówków do debugowania: gdy żądanie się nie powiedzie, nagłówki opowiadają historię. Brak wbudowanej denylisty. Brak filtrowania poświadczeń w dokumentacji. Pełne nagłówki trafiają na dysk.
Nagłówki poświadczeń w typowym żądaniu:
- Authorization: Bearer eyJhbGciOiJIUzI1NiJ9... (token JWT lub OAuth)
- Cookie: session=abc123; auth=xyz789
- X-API-Key: sk-live-abc123...
- X-Auth-Token: ghp_abc123... (token dostępu osobistego GitHub)
Te wartości uwierzytelniają żądanie. Zapisane do pliku dziennika, uwierzytelniają każde żądanie.
Potok poświadczeń
Poświadczenie zapisane do pliku dziennika nie pozostaje w jednym miejscu. Przemieszcza się:
1. Serwer WWW zapisuje do /var/log/nginx/access.log
2. Agent rotacji dzienników (logrotate) kopiuje do /var/log/nginx/access.log.1
3. Przesyłacz dzienników (Fluentd, Filebeat, Logstash) odczytuje i przesyła do agregatora
4. Agregator logów (Elasticsearch, Splunk, Datadog) indeksuje i przechowuje
5. Przechowywane przez 30-90 dni zgodnie z domyślną polityką
Poświadczenie istnieje jednocześnie we wszystkich pięciu lokalizacjach. Unieważnienie tokena sesji nie usuwa poświadczenia z agregatora logów. Pozostaje ono wyszukiwalne, eksportowalne i dostępne dla każdego, kto ma dostęp do logów, przez cały okres przechowywania.
Okno narażenia
Okno narażenia dla poświadczenia w pamięci: max(czas trwania sesji, czas życia procesu). Sesja: godziny do dni. Proces: godziny do tygodni.
Okno narażenia dla poświadczenia w logu: max(czas trwania sesji, okres przechowywania logów). Sesja: godziny do dni. Przechowywanie: 30-90 dni.
Poświadczenie skradzione z pamięci wymagało obecności atakującego w oknie sesji. Poświadczenie skradzione z logu wymaga jedynie dostępu do agregatora logów, dostępnego retrospektywnie, przez cały okres przechowywania.
MOAD-0003 vs MOAD-0004
MOAD-0003 (Wyciek kontekstu): poświadczenie w pamięci wycieka do niewłaściwego handlera żądania. Dostępne tylko w oknie procesu, przez pulę wątków. Efemeryczne.
MOAD-0004 (Zalogowany sekret): poświadczenie na dysku utrzymuje się przez rotację logów, wysyłkę logów i agregację logów. Dostępne retrospektywnie, dla każdego z dostępem do logów, przez 30–90 dni. Trwałe.
Różnica strukturalna: efemeryczne vs trwałe. Naprawa działa na innej warstwie.
Efemeryczne vs Trwałe
Rozróżnienie efemeryczne/trwałe określa powierzchnię ryzyka, warstwę naprawy oraz wymagania dotyczące reakcji na incydent.
Lista zabronionych poświadczeń na warstwie serializacji
Rozwiązanie: lista zabronionych poświadczeń na warstwie serializacji. Zanim jakakolwiek wartość nagłówka trafi do wyjścia dziennika, sprawdź nazwę nagłówka względem listy zabronionych. Zastąp wartość ciągiem [REDACTED].
CREDENTIAL_HEADERS = {
'authorization',
'cookie',
'x-api-key',
'x-auth-token',
'x-csrf-token',
'proxy-authorization',
}
def sanitize_headers(headers: dict) -> dict:
return {
k: '[REDACTED]' if k.lower() in CREDENTIAL_HEADERS else v
for k, v in headers.items()
}
Lista zabronionych należy umieścić na warstwie serializacji, a nie na warstwie zapytania logów. Redakcja na poziomie zapytania logów: działa po tym, jak poświadczenie trafiło na dysk; surowa wartość nadal istnieje, jest tylko ukryta przed wyświetleniem. Redakcja na warstwie serializacji: poświadczenie nigdy nie trafia na dysk. Surowa wartość nigdy nie wchodzi do pliku logów, shippera logów ani agregatora logów.
Testowanie listy zabronionych
Trzy wzorce testowe:
- Pozytywny: żądanie z Authorization: Bearer token123 generuje wpis logu z Authorization: [REDACTED]
- Negatywny: żądanie z nagłówkiem Content-Type: application/json tworzy wpis dziennika z zachowaną wartością
- Niewrażliwy na wielkość liter: AUTHORIZATION: Bearer token123 również powoduje [REDACTED] (nazwy nagłówków HTTP są niewrażliwe na wielkość liter)
Lista blokowanych elementów wymaga konserwacji: nowe wzorce nagłówków poświadczeń (np. niestandardowe nagłówki X-Service-Auth) wymagają jawnego dodania. Poprawka ma charakter strukturalny, ale nie jest samoutrzymująca się.
Zastosuj listę blokowanych elementów
Zespół konfiguruje format dziennika dostępu Nginx, aby uwzględniał wszystkie nagłówki żądań w celu debugowania incydentu produkcyjnego. Konfiguracja:
log_format debug_format '$remote_addr - $request - $http_authorization - $http_cookie';
access_log /var/log/nginx/debug.log debug_format;
Rozwiązują incydent i zamierzają usunąć konfigurację debugowania, ale zmiana nie trafia na produkcję przed następnym cyklem wdrożenia (7 dni później).