SQL Injection — az alkalmazás adatbázisa elleni támadás egy fajtája, amely során a támadó rosszindulatú SQL-kódot injektál a lekérdezési paraméterekbe, ezzel illetéktelen hozzáférést szerezve az adatokhoz vagy azok módosításának lehetőségét kapva. A OWASP (2025) adatai szerint az SQL Injection továbbra is az egyik kritikus biztonsági rés, amely az adatbázis teljes kompromittálódásához vezethet. SQL-kód injektálása lehetővé teszi a támadó számára, hogy rekordokat olvasson, módosítson és töröljön, bizonyos esetekben pedig hozzáférést szerezzen a szerver operációs rendszeréhez.
Főbb pontok
Az SQL Injection olyan biztonsági rés, amely akkor keletkezik, amikor az alkalmazás egy SQL-lekérdezést stringek összefűzésével hoz létre felhasználói adatokkal. A támadó egy speciálisan megszerkesztett stringet küld a lekérdezési paraméterbe, amely megváltoztatja az SQL-parancs szerkezetét. A bevitt string adat helyett az SQL-kód részévé válik, lehetővé téve a támadó számára, hogy tetszőleges lekérdezéseket hajtson végre az adatbázison. A Verizon Data Breach Report (2025) szerint az SQL Injection az összes vizsgált adatszivárgás 8%-ában jelen van.
A biztonsági rés ismertsége ellenére (első említések — az 1990-es évek vége) az SQL Injection még mindig előfordul modern alkalmazásokban. Az ok — emberi tényező: a fejlesztők megengedik a stringösszefűzést a kódban, a régi kódot nem refaktorálják, és az ORM-keretrendszereket helytelenül használják (pl. nyers lekérdezések értékek stringeken keresztüli behelyettesítésével). A Veracode (2026) adatai szerint az összes vizsgált alkalmazás körülbelül 14%-a tartalmaz legalább egy SQLi biztonsági rést.
A sikeres SQL Injection széles körű lehetőségeket biztosít a támadónak: az adatbázis bármely táblájának olvasása, beleértve a jelszóhasheket és a felhasználók személyes adatait; rekordok módosítása és törlése; adminisztratív műveletek végrehajtása (DROP TABLE, TRUNCATE); bizonyos konfigurációkban — parancsok távoli végrehajtása xp_cmdshell (MSSQL) vagy INTO OUTFILE (MySQL) segítségével. Következmények — a felhasználói adatok kiszivárgásától a rendszer feletti teljes kontroll elvesztéséig.
Az SQL injekciókat az adatbázisból történő adatkinyerés módja szerint osztályozzák. A módszer kiválasztása attól függ, hogy az alkalmazás hogyan dolgozza fel a lekérdezés eredményeit és a hibaüzeneteket. OWASP osztályozás három fő típust különböztet meg: In-band (az adatok ugyanazon a csatornán kerülnek kinyerésre), Inferential/Blind (logikai következtetések) és Out-of-band (az adatok másik csatornán keresztül kerülnek továbbításra).
| Típus | Adatkinyerés módja | Bonyolultság | Gyakoriság |
|---|---|---|---|
| In-band (klasszikus) | Közvetlenül a lekérdezés eredményén keresztül | Alacsony | Magas |
| Blind SQLi | Logikai következtetések a szerver válaszai alapján | Magas | Közepes |
| Out-of-band | Külső csatornán keresztül (DNS, HTTP) | Közepes | Alacsony |
A leggyakoribb típus. A támadó SQL-kódot injektál a lekérdezési paraméterbe, és az injekció eredménye közvetlenül látható a szerver válaszában. Két altípus: Error-based (az adatbázis hibaüzenetein keresztül) és UNION-based (az UNION SELECT operátoron keresztül). Az Error-based a hibaüzenetekből származó információkat használja, például egy MySQL szintaktikai hibát, amely felfedheti a tábla nevét vagy a lekérdezés szerkezetét. A UNION-based lehetővé teszi egy jogos lekérdezés eredményeinek kombinálását az adatbázis más tábláiból származó adatokkal.
Akkor használatos, amikor az alkalmazás nem jeleníti meg a lekérdezés eredményeit vagy a hibaüzeneteket. A támadó „igen/nem” típusú kérdéseket tesz fel, logikai feltételekkel ellátott lekérdezéseket küldve és a szerver válaszában lévő különbséget elemezve (pl. válaszidő vagy oldaltartalom). A Time-based Blind SQLi késleltetési függvényt (SLEEP, WAITFOR DELAY) használ a feltételek megerősítésére — ha az oldal tovább töltődik, a feltétel igaz. Ez a módszer nagyon lassú — egyetlen rekord kinyerése órákig is eltarthat.
# Példa Blind SQL Injection-re (time-based)
# Ha az SQLi sérülékeny, a SLEEP(2) feltétel mellett fut le
import requests
import time
payload = "' OR IF(SUBSTRING((SELECT password FROM users LIMIT 1),1,1)='a',SLEEP(2),0) -- "
url = "http://example.com/user?id=1" + payload
start = time.time()
response = requests.get(url)
elapsed = time.time() - start
# Ha a válasz >2 másodperc után érkezett — a jelszó első betűje 'a'
print(f"Time: {elapsed:.2f}s - First letter is 'a'" if elapsed > 2 else "First letter is not 'a'")
Az adatok nem HTTP-válaszon keresztül, hanem alternatív csatornákon keresztül kerülnek továbbításra: DNS-lekérdezések, HTTP-kérések egy külső szerverhez, SMTP. Akkor használatos, amikor az alkalmazás nem adja vissza a lekérdezés eredményeit és nem mutat hibákat. A MySQL támogatja a LOAD_FILE() függvényt, amely DNS-lekérdezést kezdeményezhet, az MSSQL pedig az xp_dirtree-t az adatok távoli SMB-szerverre küldéséhez. Az Out-of-band SQL Injection hatékony, de további beállításokat igényel a támadó szerverén és bizonyos adatbázis-függvények meglétét.
Az SQL Injection mechanizmusa azon alapul, hogy az SQL idézőjeleket használ a string literálokhoz. Ha az alkalmazás a felhasználói bemenetet közvetlenül az SQL-lekérdezésbe helyettesíti be escape-elés nélkül, a támadó „lezárhatja” a stringet és tetszőleges SQL-kódot adhat hozzá. Például a SELECT * FROM users WHERE name = '$input' lekérdezésben a ' OR '1'='1 behelyettesítés a lekérdezést a következővé alakítja: SELECT * FROM users WHERE name = '' OR '1'='1', ami az összes felhasználót visszaadja.
Tekintsünk egy bejelentkezési űrlapot a SELECT * FROM users WHERE username = '$user' AND password = '$pass' lekérdezéssel. Ha a támadó a username mezőbe admin' -- ír, a jelszót pedig üresen hagyja, az eredményül kapott lekérdezés a következő lesz: SELECT * FROM users WHERE username = 'admin' -- ' AND password = ''. A -- karakterek kommentálják a lekérdezés többi részét, és a jelszó-ellenőrzési feltétel kikapcsolásra kerül. A szerver visszaadja az admin felhasználó rekordját, és a támadó a jelszó ismerete nélkül belép a rendszerbe.
# Példa SQL Injection-re — hitelesítés megkerülése
# SÉRÜLÉKENY KÓD: közvetlen stringösszefűzés
def login_vulnerable(username, password):
query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
cursor.execute(query)
return cursor.fetchone() is not None
# username = "admin' --" érvényteleníti a jelszó-ellenőrzést
# BIZTONSÁGOS VÁLTOZAT: paraméterezett lekérdezés
def login_secure(username, password):
query = "SELECT * FROM users WHERE username = %s AND password = %s"
cursor.execute(query, (username, password))
return cursor.fetchone() is not None
Az UNION SELECT operátor lehetővé teszi két SELECT lekérdezés eredményeinek egyesítését. Ha a támadó talál egy sérülékeny paramétert, UNION SELECT-et ad hozzá egy másik táblából származó lekérdezéssel. Például: ' UNION SELECT username, password FROM admins --. A siker feltétele — az oszlopok számának egyeznie kell mindkét lekérdezésben. Az oszlopok száma ORDER BY segítségével határozható meg (' ORDER BY 1--, majd 2, 3... hibaig). Az oszlopok számának ismeretében a támadó UNION SELECT-et helyettesít be ugyanannyi mezővel.
A mobilalkalmazások SQL Injection-nel szembesülnek mind a szerveroldalon (API), mind a kliensoldalon — a helyi adatbázisokban (SQLite, Realm). Bár a szerveroldali SQLi kockázata a mobil API-ban hasonló a webalkalmazásokéhoz, a helyi adatbázis egy további vektort hoz létre. Ha az alkalmazás adatokat tárol SQLite-ban és stringösszefűzéssel hajt végre lekérdezéseket, az API-n keresztül a helyi adatbázisba került rosszindulatú adatok a későbbi feldolgozás során SQLi-t okozhatnak.
Az eszközön lévő helyi SQLite adatbázis szintén sérülékeny SQL Injection-re, ha az alkalmazás stringösszefűzéssel hozza létre a lekérdezéseket. Content Providers Androidon és Core Data iOS-en alapértelmezés szerint paraméterezést használ, de a nyers lekérdezések a fejlesztő figyelmét igénylik. Az SQLite nem támogat több lekérdezést pontosvesszőn keresztül, ami korlátozza a támadó lehetőségeit, de nem véd az adatok WHERE-feltételeken keresztüli olvasása ellen. Mindig használjon selectionArgs paramétereket Androidon és NSPredicate-et paraméterekkel iOS-en.
Az API, amelyhez a mobilalkalmazás csatlakozik, ugyanolyan sérülékeny, mint bármely webszerver. A mobilfejlesztők gyakran gondolják, hogy az SQLi csak a backend problémája, de a biztonsági rés az API-endpoint szintjén keletkezik, amely paramétereket fogad a klienstől. A felelősség megosztása nem véd: ha a backend-fejlesztő elfelejtette paraméterezni a lekérdezést, a felhasználó mobilalkalmazása támadási vektorrá válik. Követelje meg a backendtől az ORM vagy prepared statements használatát.
// Példa SQL Injection-re helyi SQLite-ban Androidon
// SÉRÜLÉKENY KÓD: közvetlen összefűzés
fun getUserVulnerable(db: SQLiteDatabase, userId: String): Cursor {
return db.rawQuery(
"SELECT * FROM users WHERE id = $userId", null
)
}
// BIZTONSÁGOS VÁLTOZAT: paraméterezés selectionArgs segítségével
fun getUserSecure(db: SQLiteDatabase, userId: String): Cursor {
return db.rawQuery(
"SELECT * FROM users WHERE id = ?",
arrayOf(userId)
)
}
Az SQL Injection elleni védelem egy egyszerű elven alapul: soha ne bízzon a felhasználói bemenetben az SQL-lekérdezésekben. Az egyetlen megbízható módszer — a lekérdezések paraméterezése (prepared statements), ahol az SQL-kód és az adatok külön kerülnek továbbításra. Minden más módszer — escape-elés, validáció, WAF — további védelmi rétegek, de nem helyettesítik a paraméterezést. Az OWASP (2025) adatai szerint a paraméterezés az SQL Injection támadások 100%-át megakadályozza.
A prepared statements használatakor az SQL-lekérdezést először az adatbázis-szerver lefordítja adatok nélkül, majd a paraméterértékek külön kerülnek továbbításra. Az adatbázis a paramétereket adatként kezeli, nem végrehajtható kódként. Még ha a támadó ' OR '1'='1-et küld is, az adatbázis stringértékként értelmezi, nem SQL-kódként. A prepared statements-et minden modern nyelv és keretrendszer támogatja: PDO PHP-ban, PreparedStatement Java-ban, cursor.execute Pythonban.
A modern ORM-ek (Hibernate, Entity Framework, SQLAlchemy, Room) automatikusan paraméterezést használnak a lekérdezések végrehajtásakor, hacsak a fejlesztő nem vált nyers lekérdezésekre. Az ORM azonban nem véd teljes mértékben: az olyan konstrukciók, mint a @Query(value = "SELECT * FROM users WHERE name = :name", nativeQuery = true) a JPA-ban megkövetelik a paraméterek nevesített paramétereken keresztüli átadását, nem pedig összefűzést. A Query Builderek (Knex, jOOQ) szintén alapértelmezés szerint paraméterezik a lekérdezéseket, ha nem használnak nyers módszereket.
A speciális karakterek escape-elése (mysql_real_escape_string) — egy elavult módszer, amely nem véd az SQL Injection minden típusa ellen. Probléma: az escape-elés a kódolástól függ, és több bájtos kódolások használatával megkerülhető (pl. GBK ázsiai rendszerekben). Csak olyan régi kódban használjon escape-elést, ahol a paraméterezés nem lehetséges, és mindig a bemeneti adatok típusának szigorú validációjával együtt.
| Módszer | Hatékonyság | Ajánlás |
|---|---|---|
| Prepared Statements | 100% | Kötelező minden lekérdezéshez |
| ORM (helyes használat) | 99% | Ajánlott |
| Stringek escape-elése | 70% (kódolástól függ) | Csak régi kód |
| Bemenet validációja (fehér lista) | 50% (csak számokhoz) | Kiegészítő |
| WAF (Web Application Firewall) | 60% | Kiegészítő |
Az alkalmazás fiókjának minimálisan szükséges jogosultságokkal kell rendelkeznie: SELECT, INSERT, UPDATE, DELETE — csak azokon a táblákon, amelyekre az alkalmazásnak valóban szüksége van. Tiltsa meg a DROP, TRUNCATE, CREATE használatát az alkalmazás fiókja számára. Ez korlátozza a kárt még sikeres SQL Injection esetén is: a támadó nem tudja törölni a táblákat vagy adminisztratív műveleteket végrehajtani.
Az SQL Injection-re történő rendszeres tesztelésnek a biztonságos fejlesztési pipeline részét kell képeznie. A statikus elemzés, dinamikus szkennelés és kézi penetrációs teszt kombinációja adja a legjobb eredményeket. A Synopsys Cybersecurity Report (2025) szerint az automatikus szkennerek az SQLi biztonsági rések akár 70%-át is megtalálják, de az összetett Blind támadások kézi tesztelést igényelnek.
Mobilalkalmazások esetében a helyi SQLite elemzése is fontos: ellenőrizze az összes rawQuery hívást, ContentProvider lekérdezést és Room lekérdezést rawQuery-val. Eszközök: Android Studio Lint (SQLi észlelése SQLite-ban), MobSF (Mobile Security Framework) az APK/IPA automatikus statikus és dinamikus elemzéséhez. Javasolt továbbá az API-endpointok tesztelése sqlmap segítségével a mobilalkalmazás forgalmának proxy-elfogásával.
Gyakran ismételt kérdések
Az SQL Injection a relációs adatbázisokat támadja SQL-lekérdezéseken keresztül. A NoSQL Injection a nem-relációs adatbázisokat (MongoDB, Couchbase) támadja azok lekérdezési operátorain keresztül ($gte, $ne, $where). MongoDB-ben injekció akkor lehetséges, ha az alkalmazás BSON-dokumentumot hoz létre JSON stringből. A védelmi mechanizmusok hasonlóak: paraméterezés és típusvalidáció.
Keresse meg az összes helyet, ahol SQL-lekérdezések stringösszefűzéssel jönnek létre felhasználói adatokkal. Keressen olyan mintákat, mint a "SELECT ... WHERE id = " + userId vagy f"UPDATE ... SET name = '{name}'". Minden ilyen string potenciális SQL injekció. Cserélje le őket paraméterezett lekérdezésekre vagy prepared statements-re.
Az ORM-keretrendszerek csak akkor védenek automatikusan, ha azok Query Builder metódusait és nevesített paramétereit használja. Ha nyers lekérdezéseket használ (nativeQuery a JPA-ban, rawQuery a Room-ban), a védelem nem működik — a paramétereket előkészített kifejezéseken keresztül kell átadni, nem stringösszefűzéssel.
A Second-Order SQL Injection olyan támadás, ahol a rosszindulatú adatok biztonságosként tárolódnak az adatbázisban, de aztán egy másik lekérdezésben escape-elés nélkül kerülnek felhasználásra. Például a támadó regisztrál a ' OR '1'='1 felhasználónévvel. Az adatok stringként tárolódnak — regisztrációkor nincs támadás. De ha egy másik lekérdezés a felhasználónevet paraméterezés nélkül helyettesíti be az SQL-be, az injekció aktiválódik.
A NoSQL Injection potenciálisan veszélyesebb a fejlesztők alacsonyabb tudatossága miatt. A fejlesztők ismerik az SQL Injection-t és többségük ORM-et használ, de a NoSQL Injection-ről kevesen tudnak. MongoDB-ben egy helytelenül formázott lekérdezés a gyűjtemény összes dokumentumát visszaadhatja. Védelem — ugyanazok a prepared statements (BSON-paraméterezés) és a bemeneti adatok szigorú validációja.
Összefoglaló
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is