A lecke végére el tudod magyarázni az injekció lényegét (a kód és az adat összekeveredése), le tudod olvasni egy SQL-injekció működését, és tudod, miért paraméterezett lekérdezés a fő védelem.
Miért veszélyes az összefűzött lekérdezés?
A Kurzuspont kurzuskereső funkciója az adatbázisból kérdezi le a kurzust az azonosítója alapján. Ha a szerver a kapott azonosítót szövegként egy SQL-lekérdezésbe (SQL: Structured Query Language, a relációs adatbázisok lekérdezőnyelve) fűzi, a bemenet a lekérdezés szintaxisának részévé válhat. A támadó ekkor nem adatot ad, hanem utasítást adatként becsomagolva. Az injekció (injection) lényege tehát nem a furcsa karakter, hanem a kód és az adat összekeverése. Ugyanez az elv fennáll más értelmezőknél is: parancsértelmező, sablonmotor. Az OWASP Top 10:2025 listán az injekció az 5. kategória (A05).
Kipróbálva: összefűzött és paraméterezett lekérdezés
Egy kis adatbázis három kurzussal: kettő nyilvános (nyilvanos = 1), egy belső, nem nyilvános. A kereső a nyilvános kurzusokat adja vissza az azonosító szerint. Ugyanazt a bemenetet két módon adtuk át az SQLite adatbázisnak (Node.js 24, beépített node:sqlite modul):
// ÖSSZEFŰZÖTT (veszélyes):const naiv = `SELECT id, cim FROM kurzus WHERE nyilvanos = 1 AND id = '${bemenet}'`;
// PARAMÉTEREZETT (biztonságos):const par = db.prepare('SELECT id, cim FROM kurzus WHERE nyilvanos = 1 AND id = ?');
par.all(bemenet);
1. Normál bemenet: webprog
SQL (összefűzött): SELECT id, cim FROM kurzus WHERE nyilvanos = 1 AND id = 'webprog'
-> [{"id":"webprog","cim":"Webprogramozás 1."}]
SQL (paraméterezett): ... id = ? [paraméter: "webprog"]
-> [{"id":"webprog","cim":"Webprogramozás 1."}]
Mindkét változat helyesen működik.
2. Támadó bemenet: x' OR '1'='1
SQL (összefűzött): SELECT id, cim FROM kurzus WHERE nyilvanos = 1 AND id = 'x' OR '1'='1'
-> [{"id":"webprog",...},{"id":"adatbazisok",...},{"id":"belso","cim":"Belső oktatói értekezlet"}]
SQL (paraméterezett): ... id = ? [paraméter: "x' OR '1'='1"]
-> []
Az összefűzött változatban a bemenet idézőjele lezárta a szöveget, az OR '1'='1' pedig új feltételt adott, amely mindig igaz. Mivel az AND erősebben köt, mint az OR, a nyilvanos = 1 megszorítás hatástalan lett, és a belső értekezlet is megjelent. A paraméterezett változatban a teljes bemenet egyetlen szöveges érték maradt: ilyen azonosítójú kurzus nincs, ezért a válasz üres.
3. Még célzottabb bemenet: x' OR nyilvanos = 0 --
SQL (összefűzött): SELECT id, cim FROM kurzus WHERE nyilvanos = 1 AND id = 'x' OR nyilvanos = 0 --'
-> [{"id":"belso","cim":"Belső oktatói értekezlet"}]
SQL (paraméterezett): ... id = ? [paraméter: "x' OR nyilvanos = 0 --"]
-> []
A -- az SQL-ben megjegyzést kezd, így a támadó a lekérdezés hátralévő részét is eltüntette. Itt kifejezetten a belső kurzust kapta meg.
flowchart LR
V[Felhasználói érték] --> P[Paraméter]
Q[Állandó SQL-szerkezet] --> E[Adatbázismotor]
P --> E
E --> R[Adatként értelmezett érték]
Miért működik a paraméterezés?
A paraméterezett lekérdezésnél (prepared statement) az SQL-szerkezet és a felhasználói érték külön jut az adatbázishoz. Az adatbázis előbb értelmezi a lekérdezés szerkezetét (... id = ?), és a paraméter csak ezután kerül a helyére értékként, soha nem utasításként. Az OWASP SQL-injekció elleni útmutatója szerint ez az elsődleges védelem: az adatbázis a bemenetet adatként kezeli, nem kódként.
Az útmutató a következő sorrendet adja:
Paraméterezett lekérdezés (prepared statement).
Tárolt eljárások, ha biztonságosan (paraméterekkel, nem dinamikus SQL-lel) készültek.
Engedélyezőlistás bemenet-ellenőrzés ott, ahol paraméter nem használható (például tábla- vagy oszlopnév, rendezési irány): a felhasználói értéket ismert, jó értékekre kell leképezni.
Karakterek escape-elése: az útmutató ezt erősen ellenzi, mert törékeny, és nem garantál védelmet.
Kiegészítő védelem a legkisebb jogosultság elve: az alkalmazás adatbázis-fiókja csak azt tehesse meg, amire szüksége van (ne legyen adminisztrátori fiók), és alkalmazásonként külön adatbázis-felhasználó legyen. Így egy hiba kisebb kárt okoz.
Más értelmezők, ugyanaz a gondolat
Az injekció akkor jön létre, ha a program olyan szöveget épít, amelyet egy másik értelmező utasításként olvas: SQL-motor, operációs rendszer parancssora, sablonmotor, keresőszolgáltatás lekérdezőnyelve. A védelem mindig ugyanaz az elv: az utasítás szerkezete és a felhasználói érték külön csatornán jusson el az értelmezőhöz, vagy az értéket az adott értelmező szabályai szerint kell biztonságosan kezelni. Az XSS (8.3) rokon gondolat: ott az értelmező a böngésző HTML-elemzője.
Végigvezetett példa: a Kurzuspont kurzuskeresője
Lépés
Döntés
A kereső lekérdezése
Paraméterezett lekérdezés, az azonosító csak értékként kerül be.
Rendezési irány a felületről (ASC/DESC)
Engedélyezőlista: csak ez a két érték mehet be a lekérdezésbe.
Az alkalmazás adatbázis-fiókja
Csak olvasás a kurzus táblán; a belső táblákhoz nincs joga.
A belső kurzus (nyilvanos = 0)
A szabályt a lekérdezés és a jogosultsági réteg is érvényesíti (7.4).
Így még egy hibás kód sem adná ki a belső kurzusokat.
Gyakori tévhitek
Állítás
Pontosítás
„Elég minden különleges karaktert törölni.”
A helyes kezelés az értelmezési környezettől függ; SQL-nél paraméterezés kell.
Injekció: amikor az adatból utasítás lesz
Célok
A lecke végére el tudod magyarázni az injekció lényegét (a kód és az adat összekeveredése), le tudod olvasni egy SQL-injekció működését, és tudod, miért paraméterezett lekérdezés a fő védelem.
Miért veszélyes az összefűzött lekérdezés?
A Kurzuspont kurzuskereső funkciója az adatbázisból kérdezi le a kurzust az azonosítója alapján. Ha a szerver a kapott azonosítót szövegként egy SQL-lekérdezésbe (SQL: Structured Query Language, a relációs adatbázisok lekérdezőnyelve) fűzi, a bemenet a lekérdezés szintaxisának részévé válhat. A támadó ekkor nem adatot ad, hanem utasítást adatként becsomagolva. Az injekció (injection) lényege tehát nem a furcsa karakter, hanem a kód és az adat összekeverése. Ugyanez az elv fennáll más értelmezőknél is: parancsértelmező, sablonmotor. Az OWASP Top 10:2025 listán az injekció az 5. kategória (A05).
Kipróbálva: összefűzött és paraméterezett lekérdezés
Egy kis adatbázis három kurzussal: kettő nyilvános (
nyilvanos = 1), egy belső, nem nyilvános. A kereső a nyilvános kurzusokat adja vissza az azonosító szerint. Ugyanazt a bemenetet két módon adtuk át az SQLite adatbázisnak (Node.js 24, beépítettnode:sqlitemodul):// ÖSSZEFŰZÖTT (veszélyes): const naiv = `SELECT id, cim FROM kurzus WHERE nyilvanos = 1 AND id = '${bemenet}'`; // PARAMÉTEREZETT (biztonságos): const par = db.prepare('SELECT id, cim FROM kurzus WHERE nyilvanos = 1 AND id = ?'); par.all(bemenet);1. Normál bemenet:
webprogMindkét változat helyesen működik.
2. Támadó bemenet:
x' OR '1'='1Az összefűzött változatban a bemenet idézőjele lezárta a szöveget, az
OR '1'='1'pedig új feltételt adott, amely mindig igaz. Mivel azANDerősebben köt, mint azOR, anyilvanos = 1megszorítás hatástalan lett, és a belső értekezlet is megjelent. A paraméterezett változatban a teljes bemenet egyetlen szöveges érték maradt: ilyen azonosítójú kurzus nincs, ezért a válasz üres.3. Még célzottabb bemenet:
x' OR nyilvanos = 0 --A
--az SQL-ben megjegyzést kezd, így a támadó a lekérdezés hátralévő részét is eltüntette. Itt kifejezetten a belső kurzust kapta meg.flowchart LR V[Felhasználói érték] --> P[Paraméter] Q[Állandó SQL-szerkezet] --> E[Adatbázismotor] P --> E E --> R[Adatként értelmezett érték]Miért működik a paraméterezés?
A paraméterezett lekérdezésnél (prepared statement) az SQL-szerkezet és a felhasználói érték külön jut az adatbázishoz. Az adatbázis előbb értelmezi a lekérdezés szerkezetét (
... id = ?), és a paraméter csak ezután kerül a helyére értékként, soha nem utasításként. Az OWASP SQL-injekció elleni útmutatója szerint ez az elsődleges védelem: az adatbázis a bemenetet adatként kezeli, nem kódként.Az útmutató a következő sorrendet adja:
Kiegészítő védelem a legkisebb jogosultság elve: az alkalmazás adatbázis-fiókja csak azt tehesse meg, amire szüksége van (ne legyen adminisztrátori fiók), és alkalmazásonként külön adatbázis-felhasználó legyen. Így egy hiba kisebb kárt okoz.
Más értelmezők, ugyanaz a gondolat
Az injekció akkor jön létre, ha a program olyan szöveget épít, amelyet egy másik értelmező utasításként olvas: SQL-motor, operációs rendszer parancssora, sablonmotor, keresőszolgáltatás lekérdezőnyelve. A védelem mindig ugyanaz az elv: az utasítás szerkezete és a felhasználói érték külön csatornán jusson el az értelmezőhöz, vagy az értéket az adott értelmező szabályai szerint kell biztonságosan kezelni. Az XSS (8.3) rokon gondolat: ott az értelmező a böngésző HTML-elemzője.
Végigvezetett példa: a Kurzuspont kurzuskeresője
ASC/DESC)kurzustáblán; a belső táblákhoz nincs joga.nyilvanos = 0)Így még egy hibás kód sem adná ki a belső kurzusokat.
Gyakori tévhitek
Röviden
Ellenőrző kérdések
x' OR '1'='1bemenet?Tanulási források