8.5 Input validáció

← 8. Production-ready projekt építés

8.5 Input validáció és adattisztítás

Áttekintő

Minden production-ready alkalmazásnak van egy alapvető szabálya, amit ha nem tartasz be, előbb-utóbb megégeted magad:

Soha ne bízz a felhasználói inputban.

Nem azért, mert a felhasználók rosszindulatúak (bár néha azok), hanem mert tévednek, elgépelnek, váratlan formátumot használnak – és a kódod ennek ellenére is helyesen kell, hogy működjön. Ez az alfejezet arról szól, hogyan szűröd és tisztítod meg az adatokat, mielőtt bármit csinálsz velük.

Miért számít ez az állásinterjún? A „hogyan validálod a felhasználói inputot?" típusú kérdés szinte minden web-fejlesztői interjún előjön. Ha az a válaszod, hogy „a frontend ellenőrzi", azonnal látszik, hogy nem értesz a production gondolkodásmódhoz.

Miért számít ez production-ban? Validáció nélkül: adatbázisban szemét adatok, elérhető hibák a felhasználónak, biztonsági rések. Validációval: megbízható, kiszámítható rendszer.


Részletes leírás

„Soha ne bízz a felhasználói inputban" – mit jelent ez pontosan?

Képzeld el, hogy van egy regisztrációs formód. A felhasználó megadja az email-t és az életkorát. Mi jöhet be az életkor mezőbe?

  • 25 – ez rendben van
  • -5 – negatív szám
  • 999 – valószínűtlenül magas
  • huszonöt – szöveg szám helyett
  • `` (üres string) – semmi
  • <script>alert('xss')</script> – rosszindulatú kód

A kódod mind a hat esettel találkozni fog éles környezetben. Validáció nélkül valamelyik összeomlást okoz, adatbázisszennyezést, vagy biztonsági rést.


Validáció vs. sanitizáció – nem ugyanaz

Sokan összekeverik ezt a két fogalmat. Fontos a különbség:

Validáció = eldöntöd, hogy az input érvényes-e, és ha nem, visszautasítod.

Például: az email mezőbe nem kerülhet üres string és érvényes email formátumot kell követnie. Ha nem felel meg, hibaüzenetet adsz vissza.

Sanitizáció (adattisztítás) = az inputot megváltoztatod, hogy biztonságos vagy megfelelő formátumú legyen.

Például: a beküldött szövegből kivágod a vezető/záró szóközöket (" hello ""hello"), vagy HTML-karaktereket enkódolsz, hogy ne lehessen scripteket injektálni.

A kettőt általában egymás után alkalmazod:

  1. Először sanitizálod (trimmelés, normalizálás)
  2. Aztán validálod (érvényes-e a tisztított adat?)

Kliens oldali vs. szerver oldali validáció

Ez az egyik legfontosabb megkülönböztetés, amit tudnod kell:

Kliens oldaliSzerver oldali
Hol fut?Böngészőben (JavaScript)Szerveren (backend)
CéljaUX javítása, azonnali visszajelzésValódi adatbiztonság
Megkerülhető?Igen – bárki kikapcsolhatjaNem – mindig lefut
Szükséges?AjánlottKötelező

A kulcsgondolat: A kliens oldali validáció UX-eszköz, nem biztonsági eszköz.

Ha csak a böngészőben validálsz, bárki küldhet direkt HTTP kérést az API-odra a böngésző megkerülésével (pl. curl-lal vagy Postman-nel). A szerver oldali validáció mindig kötelező.

Jó gyakorlat:
Kliens oldali validáció → gyors visszajelzés a felhasználónak
Szerver oldali validáció → valódi adatbiztonság
Mindkettő egyszerre → production-ready megközelítés

Tipikus validálási esetek

1. Kötelező mező (required)

Az egyik legegyszerűbb és leggyakrabban elfelejtett ellenőrzés.

# Python
def validate_required(value, field_name):
    if value is None or str(value).strip() == "":
        raise ValueError(f"{field_name} megadása kötelező")
// JavaScript
function validateRequired(value, fieldName) {
    if (value === null || value === undefined || String(value).trim() === "") {
        throw new Error(`${fieldName} megadása kötelező`);
    }
}

2. Email formátum

Ne írj saját regex-et email validáláshoz – használd a nyelved/frameworköd beépített eszközét.

# Python – email_validator könyvtár
from email_validator import validate_email, EmailNotValidError

try:
    valid = validate_email("felhasznalo@pelda.hu")
except EmailNotValidError as e:
    print(f"Hibás email: {e}")
// PHP – beépített filter_var
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    throw new \InvalidArgumentException("Érvénytelen email cím");
}
// JavaScript – egyszerű regex CSAK UX célra (kliens oldal)
// Szerveren mindig könyvtárat használj!
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
    showError("Érvénytelen email formátum");
}

3. Szám és tartomány

# Python
def validate_age(age):
    try:
        age = int(age)
    except (ValueError, TypeError):
        raise ValueError("Az életkor szám kell legyen")
    
    if age < 0 or age > 120:
        raise ValueError("Az életkor 0 és 120 közé kell essen")
    
    return age

4. Hossz ellenőrzés

// JavaScript
function validatePassword(password) {
    if (password.length < 8) {
        throw new Error("A jelszó legalább 8 karakter hosszú kell legyen");
    }
    if (password.length > 128) {
        throw new Error("A jelszó maximum 128 karakter lehet");
    }
}

5. Típus ellenőrzés

Különösen fontos JSON API-knál, ahol a kliens bármilyen típust küldhet.

# Python – típus ellenőrzés API inputnál
def validate_product_data(data):
    if not isinstance(data.get("price"), (int, float)):
        raise ValueError("Az ár szám kell legyen")
    if not isinstance(data.get("name"), str):
        raise ValueError("A név szöveg kell legyen")
    if not isinstance(data.get("in_stock"), bool):
        raise ValueError("Az 'in_stock' mező igaz/hamis értéket várunk")

Sanitizáció a gyakorlatban

Trimmelés (szóközök eltávolítása)

Az egyik leggyakoribb – és leginkább elfelejtett – lépés.

# Mindig trim-eld a szöveges inputot!
name = request.form.get("name", "").strip()
email = request.form.get("email", "").strip().lower()
const name = req.body.name?.trim() ?? "";
const email = req.body.email?.trim().toLowerCase() ?? "";

Ha nem trim-elted, " admin " és "admin" különböző felhasználóként kerülhet az adatbázisba.

HTML escape (XSS megelőzés)

Ha a felhasználó által bevitt szöveget HTML-be rendereled vissza, enkódold:

# Python – html modul
import html
user_comment = html.escape(raw_comment)
# "<script>alert('xss')</script>" → "&lt;script&gt;alert('xss')&lt;/script&gt;"
// PHP – htmlspecialchars
$safe_output = htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');

Fontos: Modern frameworkök (Laravel Blade, Django templates, React JSX) alapból enkódolnak HTML-t, ha helyesen használod őket. De tudnod kell, hogy ez mikor és miért történik.


Visszajelzés validációs hibáról

A validáció nem csak arról szól, hogy visszautasítod a hibás inputot – arról is, hogy hasznos hibaüzenetet adsz.

Rossz visszajelzés:

Hiba: 400 Bad Request

Jó visszajelzés:

{
  "errors": {
    "email": "Érvénytelen email cím formátum",
    "password": "A jelszó legalább 8 karakter hosszú kell legyen",
    "age": "Az életkor 0 és 120 közé kell essen"
  }
}

Elvek a jó hibaüzenethez:

  • Specifikus: melyik mező hibás?
  • Cselekvésre ösztönző: mit kell javítani?
  • Nem technikai: nem stack trace, nem adatbázis-hiba
  • Összes hiba egyszerre: ne csak az első hibát add vissza

Validáció elhelyezése az alkalmazásban

HTTP kérés → [Router] → [Validáció] → [Üzleti logika] → [Adatbázis]
                              ↓
                        Ha érvénytelen:
                        400 Bad Request + hibák listája

A validáció a legelső réteg, mielőtt az üzleti logika egyáltalán lefutna.


Életszerű példák

Példa 1: Regisztrációs form handler – validáció nélkül vs. validációval

Validáció nélkül (tutorial-kód):

# ROSSZ – soha ne csinálj ilyet production-ban
@app.route("/register", methods=["POST"])
def register():
    username = request.form["username"]
    email = request.form["email"]
    password = request.form["password"]
    age = request.form["age"]
    
    # Közvetlenül az adatbázisba – minden ellenőrzés nélkül
    db.execute(
        "INSERT INTO users (username, email, password, age) VALUES (?, ?, ?, ?)",
        (username, email, hash_password(password), age)
    )
    return "Sikeres regisztráció!"

Mi mehet rosszul?

  • age értéke "huszonöt" → adatbázis hiba, ami kiszivárog a felhasználónak
  • email értéke üres → kerülhet üres email az adatbázisba
  • username hossza ezer karakter → adatbázis column overflow
  • password üres → üres hash kerül be

Validációval (production-közelibb megközelítés):

@app.route("/register", methods=["POST"])
def register():
    errors = {}
    
    # Sanitizáció először
    username = request.form.get("username", "").strip()
    email = request.form.get("email", "").strip().lower()
    password = request.form.get("password", "")
    age_raw = request.form.get("age", "").strip()
    
    # Validáció
    if not username:
        errors["username"] = "A felhasználónév megadása kötelező"
    elif len(username) < 3 or len(username) > 50:
        errors["username"] = "A felhasználónév 3-50 karakter hosszú lehet"
    
    if not email:
        errors["email"] = "Az email cím megadása kötelező"
    elif not is_valid_email(email):
        errors["email"] = "Érvénytelen email formátum"
    
    if not password:
        errors["password"] = "A jelszó megadása kötelező"
    elif len(password) < 8:
        errors["password"] = "A jelszó legalább 8 karakter hosszú kell legyen"
    
    try:
        age = int(age_raw)
        if age < 0 or age > 120:
            errors["age"] = "Az életkor 0-120 közötti szám kell legyen"
    except ValueError:
        errors["age"] = "Az életkor érvényes szám kell legyen"
    
    # Ha van hiba, visszaadjuk az összeset
    if errors:
        return jsonify({"errors": errors}), 400
    
    # Csak ekkor fut az üzleti logika
    db.execute(
        "INSERT INTO users (username, email, password_hash, age) VALUES (?, ?, ?, ?)",
        (username, email, hash_password(password), age)
    )
    return jsonify({"message": "Sikeres regisztráció!"}), 201

Példa 2: A "csak JavaScript-ben validálok" csapda

Egy junior fejlesztő csak frontend validációt írt:

// Frontend validáció (böngészőben fut)
document.getElementById("register-form").addEventListener("submit", (e) => {
    const age = document.getElementById("age").value;
    if (isNaN(age) || age < 0 || age > 120) {
        e.preventDefault();
        showError("Érvénytelen életkor");
    }
});

Egy tesztelő (vagy rosszindulatú felhasználó) terminálból:

curl -X POST https://app.pelda.hu/register \
  -d "username=test&email=test@test.hu&password=12345678&age=INJECTED_PAYLOAD"

A böngésző JavaScript egyáltalán nem futott le. A szerver megkapta az INJECTED_PAYLOAD értéket validáció nélkül.

Példa 3: Laravel és PHP keretrendszer – validáció beépítve

Modern keretrendszerek beépített validációt nyújtanak:

// Laravel Controller
public function store(Request $request)
{
    // A framework validálja, és automatikusan 422-t ad vissza ha hibás
    $validated = $request->validate([
        'username' => 'required|string|min:3|max:50',
        'email'    => 'required|email|unique:users,email',
        'password' => 'required|min:8|max:128',
        'age'      => 'required|integer|min:0|max:120',
    ]);
    
    // Ha idáig eljutunk, az adatok érvényesek
    User::create([
        'username'      => $validated['username'],
        'email'         => $validated['email'],
        'password_hash' => bcrypt($validated['password']),
        'age'           => $validated['age'],
    ]);
    
    return response()->json(['message' => 'Sikeres regisztráció!'], 201);
}

A keretrendszer elvégzi a validációt, és automatikusan visszaküldi a hibaüzeneteket, ha az input nem megfelelő. A te feladatod csak a szabályokat megadni.


Tesztfeladatok

1. feladat – Fogalmak ellenőrzése

Döntsd el, hogy az alábbi műveletek validáció vagy sanitizáció kategóriába esnek-e:

a) A beküldött email cím kisbetűssé alakítása
b) Ellenőrzés, hogy az email cím tartalmaz @ karaktert
c) A szöveg elejéről és végéről szóközök eltávolítása
d) Ellenőrzés, hogy a felhasználónév nem hosszabb 50 karakternél
e) HTML-karakterek enkódolása a felhasználó kommentjéből


2. feladat – Kliens vs. szerver oldal

Az alábbi szituációkban jelöld meg, hogy kliens oldali, szerver oldali, vagy mindkét oldali validáció szükséges-e, és indokold meg:

a) Regisztrációs formon az email mező formátumának ellenőrzése
b) Ellenőrzés, hogy az email cím nincs-e már regisztrálva az adatbázisban
c) Jelszó minimális hosszának ellenőrzése
d) Feltöltött kép méretének (fájlméret) ellenőrzése
e) Fizetési összeg pozitivitásának ellenőrzése egy rendelésnél


3. feladat – Hibakeresés

Az alábbi Python kódrészletben legalább 3 validációs problémát találsz. Azonosítsd őket és javasold a javítást:

@app.route("/create-post", methods=["POST"])
def create_post():
    title = request.form["title"]
    content = request.form["content"]
    author_id = request.form["author_id"]
    
    db.execute(
        "INSERT INTO posts (title, content, author_id) VALUES (?, ?, ?)",
        (title, content, author_id)
    )
    return "Post létrehozva!"

4. feladat – Hibaüzenet minőség

Értékeld az alábbi API hibaválaszokat 1-5-ös skálán (5 = legjobb) és indokold:

A válasz:

HTTP 500 Internal Server Error
Column 'email' cannot be null

B válasz:

HTTP 400 Bad Request
{"error": "Hibás adatok"}

C válasz:

HTTP 422 Unprocessable Entity
{
  "errors": {
    "email": "Az email cím megadása kötelező",
    "password": "A jelszó legalább 8 karakter hosszú kell legyen"
  }
}

5. feladat – Igaz/hamis állítások

Döntsd el, hogy az alábbi állítások igazak vagy hamisak, és magyarázd meg:

a) Ha a frontend validálja az inputot, a backendnek már nem kell.
b) A sanitizáció mindig megelőzi a validációt.
c) Az email validáláshoz mindig saját regex-et érdemes írni.
d) Egy API-nál szerver oldali validáció kötelező, még akkor is, ha van kliens oldali is.
e) A trim (szóköz eltávolítás) sanitizáció, nem validáció.


6. feladat – Kódkiegészítés

Az alábbi JavaScript függvény részleges validációt végez. Egészítsd ki a hiányzó ellenőrzésekkel (csak a logikát kell leírni, nem kell futtatható kódot írni):

function validateProductData(data) {
    const errors = {};
    
    // TODO: name mező: kötelező, 2-100 karakter között
    // TODO: price mező: kötelező, pozitív szám
    // TODO: quantity mező: opcionális, de ha meg van adva, egész szám, minimum 0
    
    return errors;
}

Írd le, hogy melyik ellenőrzést hogyan implementálnád (pszeudokódban vagy bármilyen nyelven).


7. feladat – Szituációs döntés

Fejlesztőként az alábbi szituációkkal találkozol. Mit teszel?

a) Egy kollégád azt mondja: „Felesleges szerver oldali validáció, a frontend úgyis ellenőrzi." Hogyan érvelsz mellette?

b) Production adatbázisban sok felhasználónak üres az email mezője, mert régebben nem volt kötelező. Hogyan előzöd meg, hogy ez a jövőben is előforduljon?

c) Egy felhasználó bejelentette, hogy az ő nevével ("O'Brien") nem tud regisztrálni – hibát kap. Mi lehet az ok, és hogyan javítod?


8. feladat – Kódelemzés

Az alábbi PHP kód mit csinál, és mi a probléma vele?

<?php
$username = $_POST['username'];
$username = trim($username);

if (strlen($username) > 0) {
    echo "Szia, " . $username . "!";
} else {
    echo "Kérjük adja meg a nevét!";
}
?>

Tipp: gondolj arra, mi történik, ha valaki ezt adja meg: <script>alert('XSS')</script>


9. feladat – Architektúra kérdés

Egy webshopban a felhasználó megad egy mennyiséget (1-99 között), amit szeretne rendelni. Tervezd meg a validáció teljes folyamatát:

  • Hol és mit validálsz a frontenden?
  • Hol és mit validálsz a backenden?
  • Mi legyen a hibaüzenet, ha érvénytelen az érték?
  • Mi a sorrend: sanitizáció vagy validáció előbb?

10. feladat – Összefoglalás

Egy junior kolléga azt mondja: „Megírtam a validációt, de csak annyit csináltam, hogy ha üres a mező, hibát adok vissza."

Milyen validációs eseteket felejtett el valószínűleg? Sorolj fel legalább 5-öt, amelyeket még érdemes lenne ellenőrizni egy tipikus felhasználói regisztrációs formon.


Fejezet: 8. Production-ready projekt építés | Alfejezet: 8.5 Input validáció és adattisztítás

Scroll to Top