Walidacja danych wejściowych to proces sprawdzania danych przychodzących pod kątem zgodności z oczekiwanym formatem, typem i zakresem wartości przed ich przetworzeniem przez aplikację. Według OWASP Input Validation Cheat Sheet (2025) brak walidacji jest pierwotną przyczyną większości krytycznych podatności. Sprawdzanie danych przychodzących to pierwsza linia obrony, która zapobiega przedostawaniu się nieprawidłowych lub złośliwych danych do systemu.
Najważniejsze
Walidacja danych wejściowych to sprawdzanie, czy dane trafiające do aplikacji od użytkownika, zewnętrznego serwisu lub innego komponentu odpowiadają oczekiwanym kryteriom. Kryteria te obejmują typ danych (ciąg znaków, liczba, data), format (e-mail, URL, telefon), zakres wartości (wiek od 18 do 120), długość (hasło od 8 do 128 znaków) oraz dozwolone znaki (tylko litery łacińskie, cyfry, myślnik). Bez walidacji aplikacja może przetworzyć dane, które spowodują błędy wykonania, uszkodzenie danych lub podatności bezpieczeństwa.
Brak walidacji danych wejściowych to pierwotna przyczyna takich podatności jak SQL Injection, XSS, Command Injection, Path Traversal i Buffer Overflow. Według MITRE CWE (2025) CWE-20 (Improper Input Validation) zajmuje drugie miejsce w rankingu najniebezpieczniejszych błędów oprogramowania. Walidacja to pierwsza linia obrony w modelu bezpieczeństwa Defense in Depth: odcina nieprawidłowe dane, zanim dotrą do innych komponentów systemu.
Walidacja odrzuca dane, które nie spełniają kryteriów. Sanityzacja (oczyszczanie) modyfikuje dane, usuwając lub kodując niebezpieczne części. Na przykład przy wprowadzaniu treści HTML walidacja może sprawdzić długość tekstu, a sanityzacja — usunąć tagi script za pomocą biblioteki HTML Purifier lub DOMPurify. Sanityzacja nie zastępuje walidacji: działają one w parze. Walidacja to polityka „dozwolone/zabronione”, sanityzacja to „oczyszczone przed użyciem”.
Walidację klasyfikuje się według głębokości sprawdzania. Walidacja formatowa jest najprostsza i najszybsza, a walidacja biznesowa — najbardziej złożona i zależna od kontekstu. Wszystkie trzy poziomy powinny być stosowane kolejno: najpierw format, potem semantyka, na końcu logika biznesowa. Pominięcie któregokolwiek poziomu może prowadzić do nieprawidłowego działania systemu lub podatności.
| Poziom | Co sprawdza | Przykład |
|---|---|---|
| Formatowa | Typ danych, długość, wyrażenie regularne | E-mail zawiera @, długość 5-100 |
| Semantyczna | Logiczna poprawność wartości | Data urodzenia nie jest w przyszłości |
| Biznesowa | Zgodność z regułami biznesowymi | Kwota przelewu nie przekracza salda |
Sprawdzanie typu danych, rozmiaru, formatu i dozwolonych znaków. Realizowana przez wyrażenia regularne, wbudowane typy języków i biblioteki walidacji. Przykłady: sprawdzanie UUID (format 8-4-4-4-12 cyfr szesnastkowych), sprawdzanie numeru telefonu (tylko cyfry, + na początku, od 7 do 15 znaków), sprawdzanie liczby całkowitej (wartość w zakresie Integer.MIN_VALUE — Integer.MAX_VALUE). Walidacja formatowa to minimalny wymagany poziom dla każdego pola wejściowego.
Sprawdzanie logicznej poprawności danych w kontekście dziedziny. Na przykład: data rozpoczęcia nie później niż data zakończenia, wiek w rozsądnych granicach dla systemu, współrzędne na terenie obsługi. Walidacja semantyczna wymaga zrozumienia kontekstu biznesowego i nie może być przeprowadzona wyłącznie na podstawie formatu. Przykład: pole „liczba biletów” może przejść walidację formatową (liczba całkowita, > 0), ale semantycznie nie może przekraczać liczby wolnych miejsc.
Najbardziej złożony poziom — sprawdzanie danych pod kątem zgodności z regułami biznesowymi aplikacji. Przykłady: użytkownik nie może usunąć jedynego administratora, kwota zamówienia nie przekracza limitu kredytowego, produkt można zamówić tylko jeśli jest dostępny. Walidacja biznesowa często wymaga zapytań do bazy danych lub zewnętrznych usług i jest wykonywana po sprawdzeniach formatowych i semantycznych. Błędy walidacji biznesowej to najczęstsze przyczyny niezadowolenia użytkowników.
Walidacja po stronie klienta (w przeglądarce lub aplikacji mobilnej) służy wygodzie użytkownika: natychmiastowa informacja zwrotna bez wysyłania danych na serwer. Jednak walidacja po stronie serwera jest jedyną niezawodną, ponieważ kod klienta zawsze można ominąć. Wyślij żądania przez narzędzia deweloperskie, Postman lub proxy (Burp Suite) — a walidacja po stronie klienta przestaje istnieć. Według PortSwigger Research (2025) ponad 90% przetestowanych aplikacji internetowych polega wyłącznie na walidacji po stronie klienta dla co najmniej jednego pola.
Walidacja po stronie klienta może wyłączać przycisk wysyłania, podświetlać błędy, pokazywać podpowiedzi. Walidacja po stronie serwera to obowiązkowe sprawdzenie każdego parametru, nawet jeśli klient już go sprawdził. Duplikowanie walidacji na obu poziomach to standardowa praktyka. Serwer powinien sprawdzać dane tak, jakby klient nie istniał. To gwarantuje ochronę przed zmodyfikowanymi żądaniami, zautomatyzowanymi atakami i złośliwymi klientami.
W sieci — atrybuty HTML5 (required, pattern, min/max, type="email") i JavaScript. W aplikacjach mobilnych — natywne walidatory pól tekstowych (InputFilter w Android, textField(:shouldChangeCharactersIn:) w iOS). React Hook Form i Formik dla React, Vuelidate dla Vue, Angular Reactive Forms — popularne biblioteki do walidacji po stronie klienta. Wszystkie obsługują niestandardowe reguły i walidację asynchroniczną (sprawdzanie unikalności loginu na serwerze).
// Przykład walidacji po stronie serwera w Express z Joi
const Joi = require('joi');
const userSchema = Joi.object({
email: Joi.string()
.email()
.required()
.max(255),
age: Joi.number()
.integer()
.min(18)
.max(120)
.required(),
password: Joi.string()
.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,128}$/)
.required()
});
app.post('/api/users', async (req, res) => {
const { error, value } = userSchema.validate(req.body);
if (error) {
return res.status(400).json({
error: error.details[0].message
});
}
// value — już sprawdzone i bezpieczne dane
const user = await User.create(value);
res.status(201).json(user);
});
Aplikacje mobilne stawiają szczególne wymagania dotyczące walidacji danych. Ekran jest mniejszy — błędy muszą być zwięzłe, klawiatura kontekstowa (numeryczna do wprowadzania liczb), a sprawdzanie — asynchroniczne, aby nie blokować interfejsu. Natywne platformy udostępniają wbudowane mechanizmy walidacji, których należy używać domyślnie. Material Design Guidelines dla Androida i Human Interface Guidelines dla iOS zawierają szczegółowe zalecenia dotyczące wyświetlania błędów walidacji.
Jetpack Compose oferuje deklaratywne podejście do walidacji przez zarządzanie stanem. Każde pole wejściowe jest powiązane ze stanem (MutableState), a błąd jest obliczany na podstawie bieżącej wartości. Biblioteka Compose Validator upraszcza tworzenie reguł: required, email, min/max length, pattern. Walidacja jest wyzwalana przy zmianie tekstu (onValueChange) lub przy próbie wysłania formularza. Zaleca się pokazywanie błędu dopiero po pierwszym przesłaniu lub po zakończeniu wprowadzania przez użytkownika (debounce 300-500ms).
SwiftUI nie ma wbudowanego mechanizmu walidacji formularzy, ale umożliwia łatwą jego implementację przez Combine i property wrappers. Użyj @State dla wartości pola i właściwości obliczanej dla błędu. Framework ValidatedPropertyKit dostarcza gotowe dekoratory: @Validated().email(), @Validated().range(18...120). Zalecenie iOS — używaj typów klawiatury (UIKeyboardType.emailAddress, .numberPad) i auto-capitalization, aby zmniejszyć liczbę błędów na poziomie wprowadzania.
Flutter udostępnia klasę Form i TextFormField z wbudowaną walidacją przez callback validator. Każde pole zwraca błąd jako ciąg znaków lub null, jeśli dane są poprawne. FormState.validate() uruchamia sprawdzanie wszystkich pól formularza. Pakiet reactive_forms do złożonych przypadków: niestandardowe walidatory, sprawdzanie asynchroniczne, dynamiczne reguły. Flutter Web i wersja mobilna używają tego samego API, co upraszcza utrzymanie.
// Przykład walidacji formularza na Flutter
Form(
key: _formKey,
child: Column(
children: [
TextFormField(
decoration: InputDecoration(labelText: 'Email'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Email is required';
}
if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$')
.hasMatch(value)) {
return 'Enter a valid email';
}
return null;
},
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
// Process valid data
}
},
child: Text('Submit'),
),
],
),
)
Nowoczesne frameworki dostarczają wbudowane walidatory, które pokrywają 80% potrzeb. Pozostałe 20% wymaga niestandardowych reguł, wyrażeń regularnych lub kompozycji istniejących. Kluczowa zasada — walidacja powinna być deklaratywna, aby można ją było łatwo czytać, testować i utrzymywać. Unikaj logiki walidacji rozproszonej po kontrolerach i ekranach — przenoś ją do oddzielnych klas lub schematów.
| Narzędzie | Platforma | Cechy |
|---|---|---|
| Joi | Node.js | Deklaratywne schematy, niestandardowe komunikaty |
| Pydantic | Python | Type hints, automatyczna walidacja modelu |
| Zod | TypeScript | Type inference, ścisła typizacja |
| javax.validation | Java | Bean Validation, @NotNull, @Size, @Pattern |
| FluentValidation | .NET | Fluent API, rulesets, reguły warunkowe |
White-list (biała lista) — określasz, jakie dane są dozwolone, wszystko inne jest odrzucane. Black-list — określasz, jakie dane są zabronione, wszystko inne jest przepuszczane. White-list jest zawsze bezpieczniejsza: dokładnie wiesz, jakie dane przejdą. Black-list wymaga przewidzenia wszystkich możliwych ataków, co jest niemożliwe. Przykład: przy sprawdzaniu wieku użyj white-list (tylko liczby od 18 do 120), a nie black-list (zakaz „0”, „-1”, „999999”).
Wyrażenia regularne to skuteczne narzędzie walidacji formatowej, ale mogą być źródłem ataków ReDoS (Regular Expression Denial of Service). Niektóre wzorce (na przykład (a+)+b) prowadzą do katastrofalnego cofania (backtracking) na długich ciągach, w pełni obciążając CPU serwera. Używaj sprawdzonych bibliotek regex i ograniczaj długość ciągu przed zastosowaniem wyrażenia regularnego. W złożonych przypadkach (e-mail, URL) używaj wbudowanych parserów języków, a nie własnych wyrażeń regularnych.
Nawet doświadczeni deweloperzy popełniają błędy przy implementacji walidacji. Najczęstsze: walidacja tylko po stronie klienta, zbyt rygorystyczne reguły (hasło „Must contain uppercase, lowercase, digit, special char, >= 12 chars, must not repeat characters”), nieinformatywne komunikaty o błędach ("Error: invalid input") i ignorowanie przypadków granicznych (spacje na początku/końcu, znaki Unicode, puste ciągi). Każdy z tych błędów pogarsza UX i może obniżyć konwersję formularzy.
if (value) nie odróżnia pustego ciągu od zera, false lub „0”Najlepsza praktyka to scentralizowany system walidacji pokryty testami jednostkowymi. Każda reguła powinna być testowana osobno: wartości graniczne, poprawne dane, typowe ataki (próby SQLi, XSS-payloads, bardzo długie ciągi). Testy regresyjne walidacji zapobiegają przypadkowemu osłabieniu reguł podczas refaktoryzacji. Używaj property-based testing (QuickCheck, fast-check) do generowania losowych danych i sprawdzania, że walidacja nie kończy się wyjątkiem.
Często zadawane pytania
Walidacja odrzuca nieprawidłowe dane, a sanityzacja je oczyszcza. Na przykład przy wprowadzaniu tekstu HTML walidacja sprawdzi maksymalną długość, a sanityzacja usunie tagi script przez DOMPurify. Oba procesy są obowiązkowe: walidacja — do kontroli formatu, sanityzacja — dla bezpieczeństwa wyjścia.
Nie, nigdy. Walidacja po stronie klienta jest łatwa do obejścia przez przechwytywanie i modyfikację żądań. Używaj narzędzi takich jak Burp Suite lub po prostu curl. Walidacja po stronie serwera to jedyny niezawodny sposób ochrony systemu. Walidacja po stronie klienta służy tylko poprawie doświadczenia użytkownika.
Sprawdzaj typ MIME (nie tylko rozszerzenie), rozmiar pliku, sygnaturę (magiczne bajty na początku pliku) przez file signature validation. Nigdy nie ufaj rozszerzeniu — zmień nazwę pliku podczas zapisu. W przypadku obrazów przekoduj je biblioteką serwerową (ImageMagick, Sharp), co usunie wbudowany kod z danych EXIF.
ReDoS (Regular Expression Denial of Service) — atak, w którym atakujący wysyła specjalnie skonstruowany ciąg, wywołujący katastrofalny backtracking w wyrażeniu regularnym. W rezultacie CPU serwera jest w pełni obciążone, a odpowiedź nie jest tworzona. Ochrona: ograniczenie długości ciągu, limity czasu dla regex, używanie sprawdzonych wzorców.
Tak, jeśli dane są wyświetlane w WebView lub używane w kontekście HTML. Jeśli backend jest skompromitowany, dane mogą zawierać złośliwy kod. Waliduj i sanityzuj wszelkie dane wyświetlane użytkownikowi, niezależnie od źródła. W aplikacjach mobilnych jest to szczególnie ważne dla komponentów hybrydowych.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również