💥 Az SQL Injection – Amikor a weboldalad saját magát árulja el

🔍 Bevezető: amikor a felhasználói adat parancsként fut le

Képzeld el, hogy készítettél egy egyszerű bejelentkezési űrlapot egy weboldalon: a felhasználó megadja a nevét és jelszavát, a háttérben pedig az alkalmazás lekérdezi az adatbázist, hogy van-e ilyen felhasználó.

Teljesen ártatlannak tűnik.

Például egy tipikus lekérdezés így nézhet ki SQL-ben:

 SELECT * FROM users WHERE username = 'geza' AND password = 'titok123'

Ez azt mondja az adatbázisnak:
„Add vissza azt a felhasználót, akinek username = geza és password = titok123.”

Most képzeld el, hogy valaki nem „geza”-t ír be, hanem ezt:

Felhasználónév: ‘ OR 1=1 —

Jelszó: akármi

Így a lekérdezés ez lesz:

SELECT * FROM users WHERE username = '' OR 1=1 --' AND password = 'akármi'

Amit az adatbázis így értelmez:

  1. username = ” – Ez hamis (üres felhasználónév nincs).
  2. OR 1=1 – Ez mindig igaz.
  3. — – Ez egy SQL megjegyzés jelölő, ami elvágja a lekérdezés többi részét (a jelszót is).

Így az egész WHERE rész gyakorlatilag így néz ki:

WHERE TRUE

Azaz az adatbázis minden sort visszaad, és az elsőt (pl. admin) felhasználva a támadó be van léptetve.

💡 A lényeg: az SQL nem „látja”, hogy ez felhasználói adat

A hagyományos SQL-lekérdezés nem különbözteti meg a programkódból származó részt és a felhasználótól érkező adatot – mindkettőt ugyanúgy kezeli. Ha tehát a felhasználó adatában SQL parancs van, az parancsként fog lefutni.

Ez az SQL Injection: amikor a felhasználó adatnak álcázva utasítást ad az adatbázisnak

⚠️ Valós példák – amikor ez nem csak elmélet

  1. 🔐 2008 – Heartland Payment Systems

Több százmillió hitelkártya-adat került ki az egyik legnagyobb amerikai kártyafeldolgozótól. Az egyik behatolási pont egy klasszikus SQL Injection volt.

  1. 🏦 2012 – LinkedIn (és mások)

SQLi segítségével szerezték meg a jelszóhash-eket.

A támadók később több másik platformra is beléptek, ahol a felhasználók ugyanazt a jelszót használták.

  1. 🛍️ 2017 – eBay szivárgás

A nyilvános API-k egyikén SQLi támadással lekérdezhetők voltak más felhasználók adatai – bizonyos feltételek mellett.

Az OWASP szerint az SQL Injection évtizedek óta a TOP 10 legveszélyesebb webes sebezhetőség között szerepel.

🧪 Interaktív példa: sebezhető Python GUI

Ha szeretnéd saját szemeddel látni, milyen egyszerű kihasználni egy ilyen hibát, próbáld ki az alábbi Python programot:

🔓 Sebezhető verzió (NE HASZNÁLD ÉLESBEN!)

import tkinter as tk
from tkinter import messagebox
import sqlite3
conn = sqlite3.connect(":memory:")
c = conn.cursor()
c.execute("CREATE TABLE users (username TEXT, password TEXT)")
c.execute("INSERT INTO users VALUES ('admin', 'admin123')")
conn.commit()

def login():
 username = entry_username.get()
 password = entry_password.get()
 query = f"SELECT * FROM users WHERE username = '{username}' AND password = '{password}'"
 print("[LEKÉRDEZÉS]:", query)
 c.execute(query)
 result = c.fetchone()
 if result:
  messagebox.showinfo("Siker", "✅ Sikeres bejelentkezés!")
 else:
  messagebox.showerror("Hiba", "❌ Hibás adatok!")
root = tk.Tk()
tk.Label(root, text="Felhasználónév:").pack()
entry_username = tk.Entry(root); entry_username.pack()
tk.Label(root, text="Jelszó:").pack()
entry_password = tk.Entry(root, show="*"); entry_password.pack()
tk.Button(root, text="Bejelentkezés", command=login).pack()

root.mainloop()

🚨 Támadás bemenet:

  • Felhasználónév: ‘ OR 1=1 —
  • Jelszó: bármi

Ez automatikusan beléptet, mert a lekérdezés minden felhasználóra igaz lesz.

🛡️ A megoldás: paraméterezett lekérdezések

A probléma gyökere, hogy a felhasználó inputja lekérdezésként értelmeződik, nem adatként.

Ezt úgy lehet elkerülni, ha paraméterezett lekérdezést használsz:

✅ Biztonságos verzió:

 

query = "SELECT * FROM users WHERE username = ? AND password = ?"
c.execute(query, (username, password))

Itt az SQLite (vagy bármely adatbázis-kezelő) már tudja, hogy a ? helyére csak érték kerülhet, nem utasítás.

Ugyanez más nyelvekben:

  • PHP (PDO):
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ? AND password = ?");

$stmt->execute([$username, $password]);

  • Java (JDBC):
PreparedStatement stmt = conn.prepareStatement("SELECT * FROM users WHERE username = ? AND password = ?");

stmt.setString(1, username);
stmt.setString(2, password);

🧰 További védekezési technikák

  • Használj ORM-et (pl. SQLAlchemy, Django ORM, Laravel Eloquent).
  • Validáld a bemenetet (különösen azonosítók, számok, sémák).
  • Soha ne adj direkt SQL hozzáférést frontendnek!
  • Használj tesztelő eszközöket (pl. OWASP ZAP, sqlmap).
  • Használj minimális adatbázis-jogosultságot.

👨‍🏫 Zárás: tanítsd, használd, figyelj

Az SQL Injection kivédése nem nehéz, de felelősségteljes fejlesztést igényel.

Sok modern keretrendszer már eleve védi a fejlesztőt, de a régi kódok, egyedi projektek és gyorstákolt megoldások gyakran még mindig nyitva hagyják a kaput.

Ha webfejlesztéssel foglalkozol, ezt a hibát ismerned kell. Ha oktatsz, mutasd meg diákjaidnak élőben. És ha rendszert építesz, teszteld le a saját megoldásaidat is.

Mert lehet, hogy valaki egyszer megpróbál beírni egy ‘ OR 1=1 — sort — és akkor már késő lesz.

Verified by MonsterInsights