Ukryte pułapki bezpieczeństwa: case sensitivity w infrastrukturze webowej
Kryzys z wielkimi i małymi literami, o którym nikt nie mówi
Budujesz aplikację webową. Na devie wszystko śmiga. Staging bez zarzutu. A na produkcji nagle wyskakują błędy bez sensu. Albo researcherzy znajdują dziury, których się nie spodziewałeś.
Często winowajcą nie jest zły kod czy brak walidacji. To coś podstępniejszego: różne części systemu traktują wielkie i małe litery inaczej.
Dlaczego wielkość liter ma znaczenie?
Wszyscy wiemy, że domainy ignorują wielkość liter. example.com, Example.Com czy EXAMPLE.COM – to jedno i to samo. Proste.
Ale co z:
- Adresami email w logowaniu?
- ID użytkowników w bazie?
- Ścieżkami plików w chmurze?
- Endpointami API od dostawców?
- Walidacją certyfikatów SSL?
Gdy infrastruktura nie zgadza się co do normalizacji (ujednolicenia wielkości liter), otwierasz drzwi dla ataków.
Prawdziwy scenariusz ataku
Wyobraź sobie: walidujesz userów po emailu. W bazie trzymasz je w lowercase. Logiczne. Ale OAuth od Google'a zwraca Anna.Kowalska@Gmail.Com z różnymi literami. Twój kod porównuje stringi bez normalizacji.
Atakujący zakłada konto na anna.kowalska@gmail.com. Potem loguje się jako Anna.Kowalska@Gmail.Com. Jeśli obsługa liter kuleje, może:
- Omijać limity zapytań (inny user)
- Tworzyć duplikaty z wyższymi prawami
- Ukrywać się przed logami bezpieczeństwa
- Dostać się do cudzych zasobów
Gorzej z IDN – międzynarodowymi domenami. Reguły Unicode dla liter różnią się językami. Turecki 'ı' bez kropki psuje proste założenia ASCII. Niektóre znaki nie mają wielkiej litery.
W chmurze jak AWS S3 klucze obiektów są case-sensitive, ale nazwy bucketów nie. Błąd tu = wyciek danych.
DNS query są case-insensitive, ale twoja walidacja może nie być. Wildcard SSL i CNAME to pułapki.
Jak zabezpieczyć infrastrukturę
1. Ustal standardy normalizacji
Rób to na poziomie appki, nie bazy. Normalizuj inputy od razu przy wejściu.
# Poprawnie: na granicy
def normalize_email(email):
return email.lower().strip()
def loguj_uzytkownika(email):
norm = normalize_email(email)
user = User.query.filter_by(email=norm).first()
return user
2. Stosuj biblioteki Unicode
Dla treści międzynarodowych nie wymyślaj koła na nowo. Użyj gotowców:
- Python:
unicodedata - JavaScript:
String.localeCompare() - Go: pakiet
stringsz Unicode
3. Testuj między systemami
Appka nie żyje w próżni. Sprawdź zachowanie z:
- API dostawcy DNS
- Walidacją SSL
- OAuth od zewnętrznych
- Chmurą storage
- Regułami CDN
Zapisz, jak każdy działa. Zapewnij spójność.
4. Waliduj inputy surowo
Nie ufaj zewnętrznym systemom. Normalizuj na każdym styku.
// Przed API callami
const normalize_api = (input, format = 'lowercase') => {
let norm = format === 'lowercase'
? String(input).toLowerCase()
: String(input);
return norm.trim();
};
5. Loguj anomalie literowe
Sygnalizuj podejrzane różnice:
def sprawdz_wielkosc(email):
norm = email.lower()
if email != norm:
logger.warning(f"Różnica liter: {email} -> {norm}")
# Szukaj ataków
6. Najlepsze praktyki NameOcean
Przy rejestracji domainów i DNS w NameOcean:
- Używaj lowercase w kodzie dla domainów
- Trzymaj rekordy DNS w jednolitym standardzie
- Korzystaj z case-insensitive API bez obaw
- Opisz strategię liter w IaC
Wnioski
Bezpieczeństwo to nie tylko hasła i HTTPS. To zrozumienie całego ekosystemu. Mała różnica w literach rozwala auth, storage i API.
Ci, co łapią to wcześnie:
- Kwestionują założenia – nie ufają normalizacji systemów
- Testują edge case'y – warianty liter w security testach
- Dokumentują – zapisują zachowanie każdego elementu
- Normalizują wszędzie – jeden standard, zero wyjątków
Twoi przyszli badacze (lub hakerzy) podziękują.