Co je to SQL injekce?
SQL injekce představují významnou hrozbu pro relační databázové modely a citlivé informace, které obsahují. Proto je naprosto nezbytná komplexní ochrana proti těmto neoprávněným pokusům o externí přístup, které jsou možné díky bezpečnostním zranitelnostem.
Co je to SQL injekce?
SQL injection je typ útoku, který využívá bezpečnostní chybu v relačních databázových systémech, které používají dotazovací jazyk SQL ke zpracování uživatelských vstupů. Útočník využívá uživatelské vstupy, které nejsou správně escapovány a obsahují speciální znaky, jako jsou dvojité pomlčky, uvozovky nebo středníky. Tyto znaky mají speciální funkce pro interpret SQL a umožňují externí manipulaci s prováděnými příkazy. SQL injekce jsou často spojovány s aplikacemi PHP a ASP, které využívají zastaralá rozhraní. V mnoha z těchto případů nejsou vstupy dostatečně očištěny, což z nich činí primární cíl útoku.
Strategickým vložením funkčních znaků může neoprávněný uživatel vložit další příkazy SQL a manipulovat se záznamy v databázi za účelem čtení, úpravy nebo mazání dat. V závažných případech mohou útočníci dokonce získat přístup k příkazové řádce systému, což jim může umožnit převzít plnou kontrolu nad databázovým serverem.
Příklad SQL injekce ukazující, jak funguje útok na databázi
Vzhledem k tomu, že zranitelné databázové servery lze rychle identifikovat a útoky typu SQL injection jsou relativně snadné, zůstává tato metoda jednou z nejčastěji používaných technik kyberzločinců po celém světě. Útočníci využívají různé strategie a zneužívají jak nově objevené, tak dlouhodobé bezpečnostní chyby v aplikacích zapojených do procesu správy dat. Abychom lépe pochopili, jak SQL injection funguje v praxi, podívejme se na dva běžné způsoby útoku jako příklady.
Příklad 1: Přístup prostřednictvím špatně escapovaného uživatelského vstupu
Pro přístup k databázi se od uživatelů obvykle vyžaduje, aby se nejprve ověřili. K tomuto účelu se běžně používají skripty, které zobrazují přihlašovací formulář obsahující pole pro uživatelské jméno a heslo. Uživatelé vyplní formulář a skript poté zkontroluje, zda v databázi existují odpovídající záznamy. Ve výchozím nastavení může databáze obsahovat tabulku s názvem users se sloupci username a password. V typické webové aplikaci mohou příslušné řádky skriptu pro přístup k databázi (pomocí pseudokódu podobného jazyku Python) vypadat takto:
uname = request.POST['username']
passwd = request.POST['password']
sql = "SELECT id FROM users WHERE username='" + uname + "' AND password='" + passwd + "'"
database.execute(sql)pythonÚtočník nyní může manipulovat s polem pro heslo pomocí SQL injekce, například zadáním password' OR 1='1, což vede k následujícímu SQL dotazu:
sql = "SELECT id FROM users WHERE username='' AND password='password' OR 1='1'"pythonTo útočníkovi poskytuje plný přístup k celé tabulce uživatelů v databázi, protože podmínka hesla se vždy vyhodnotí jako pravdivá (1='1'). Pokud se útočník přihlásí jako správce, může libovolně upravovat všechny záznamy v databázi. Stejným způsobem lze manipulovat i s polem uživatelského jména.
Příklad 2: Extrakce dat pomocí manipulace s ID
Vyhledávání informací z databáze podle ID je praktická a běžná metoda, ale také otevírá možnou bránu pro SQL injekci. Například webový server ví díky přenesenému ID v URL, které informace má vyvolat z databáze. Odpovídající skript PHP vypadá takto:
<?php
$mysqli = new mysqli("localhost", "username", "password", "database");
$id = intval($_GET['id']);
$result = $mysqli->query("SELECT * FROM table WHERE id=$id");
while ($row = $result->fetch_assoc()) {
echo print_r($row, true);
}
?>phpOčekávaná URL adresa odpovídá vzoru .../script.php?id=22. V tomto případě by byla načtena položka tabulky s ID „22“. Pokud by neoprávněná osoba měla možnost tuto URL adresu manipulovat a místo toho by odeslala požadavek jako .../script.php?id=22+OR+1=1, výsledný dotaz by způsobil načtení všech řádků v tabulce:
SELECT * FROM table WHERE id=22 OR 1=1;sqlJak zločinci nacházejí zranitelné databázové systémy?
V zásadě může být jakákoli webová stránka nebo webová aplikace, která používá databáze SQL bez připravených dotazů (připravených příkazů) nebo jiných ochranných opatření, zranitelná vůči SQL injekcím. Objevené zranitelnosti nezůstanou na internetu dlouho skryté. Ve skutečnosti existují webové stránky, které publikují aktuální seznamy známých bezpečnostních chyb – a dokonce vysvětlují, jak mohou útočníci pomocí vyhledávání Google najít odpovídající webové projekty. Pokud webová stránka vrací podrobné chybové zprávy SQL, mohou kyberzločinci tyto zprávy využít k identifikaci potenciálních zranitelností. Například přidání apostrofu na konec URL adresy, která obsahuje parametr ID, již může odhalit slabinu, jak ukazuje následující příklad:
[DomainName].com/news.php?id=5’Zranitelná webová stránka odešle zpět chybovou zprávu v následující podobě:
Query failed: You have an error in your SQL syntax…
Podobné metody lze také použít k extrakci počtu sloupců, názvů tabulek a sloupců, verze SQL nebo dokonce uživatelských jmen a hesel. Kromě toho existují různé nástroje, které mohou automatizovat jak proces zjišťování, tak provádění útoků typu SQL injection.
Jak chránit databázi před SQL injekcí
Existuje řada různých metod, které můžete použít k prevenci útoků typu SQL injection na váš databázový systém. Měli byste se zabývat všemi souvisejícími komponenty – serverem a jednotlivými aplikacemi i systémem pro správu databází.
Krok 1: Sledujte automatizované vstupy z aplikací
Při zpracování vstupů z externích nebo vestavěných aplikací je nezbytné ověřit a filtrovat odeslané hodnoty, aby se zabránilo SQL injekcím.
1. Ověřte datové typy
Každý vstup by měl odpovídat očekávanému datovému typu. Pokud je například vyžadován číselný vstup, jednoduchá validace v PHP může vypadat takto:
if (filter_var($input, FILTER_VALIDATE_INT) === false) {
throw new InvalidArgumentException("Invalid input");
}phpPodobné kontroly by měly být zavedeny pro řetězce, data nebo jiné specifické formáty.
2. Filtrování speciálních znaků
Zvláštní znaky mohou vytvářet bezpečnostní zranitelnosti, zejména v kontextu SQL nebo HTML. Bezpečným přístupem je použít htmlspecialchars() pro vstup HTML a PDO::quote() pro dotazy SQL.
3. Nevytahujte chybové hlášky
Je třeba se vyvarovat přímých chybových hlášení, která odhalují technické podrobnosti o databázi nebo systému. Místo toho zobrazte obecné hlášení, například:
echo "An error occurred. Please try again later.";
error_log("Unexpected error encountered. See system log for details.");php4. Používejte připravené příkazy
Jedním z nejúčinnějších způsobů, jak zabránit SQL injekcím, je použití připravených příkazů. V tomto přístupu se příkazy SQL a parametry odesílají samostatně, takže nelze spustit škodlivý kód. Zde je ukázka implementace v PHP pomocí PDO (PHP Data Objects):
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->bindParam(':id', $user_id, PDO::PARAM_INT);
$stmt->execute();phpSystém správy databáze automaticky zajišťuje bezpečné zpracování vstupních údajů.
Krok 2: Zajistěte komplexní ochranu serveru
Bezpečnost serveru, na kterém běží váš systém pro správu databází, také hraje klíčovou roli v prevenci SQL injekcí. Klíčovým opatřením je posílení operačního systému podle následujících osvědčených postupů:
- Nainstalujte nebo povolte pouze aplikace a služby, které jsou nezbytné pro provoz databáze.
- Odstraňte všechny nepoužívané nebo nepotřebné uživatelské účty.
- Zajistěte, aby byly všechny relevantní aktualizace systému a softwaru nainstalovány bezodkladně.
- Aplikujte zásadu minimálních oprávnění, aby uživatelé a služby měli pouze minimální nezbytná oprávnění.
V závislosti na bezpečnostních požadavcích vašeho webového projektu byste měli zvážit další ochranná opatření:
- Systémy detekce narušení (IDS) a systémy prevence narušení (IPS): Tyto systémy používají různé metody detekce k včasné identifikaci útoků, vydávání výstrah a – v případě použití IPS – automatickému spouštění protiopatření.
- Brána aplikační vrstvy (ALG): ALG monitoruje a filtruje provoz mezi aplikacemi a webovými prohlížeči přímo na úrovni aplikace.
- Webová aplikační brána (WAF): WAF specificky chrání webové aplikace před SQL injekcemi a cross-site scriptingem (XSS) tím, že blokuje nebo čistí podezřelé požadavky.
- Přístup Zero Trust: Tento moderní bezpečnostní model zajišťuje, že každý pokus o přístup – bez ohledu na jeho původ – je ověřen a autentizován předtím, než je přístup povolen.
- Pravidla brány firewall a segmentace sítě: Jsou nezbytné pro dlouhodobé minimalizování plochy útoku.
- Pravidelné audity IT bezpečnosti a penetrační testy: Pomáhají odhalit a opravit zranitelnosti v rané fázi.
Krok 3: Zabezpečte databázi a používejte bezpečný kód
Stejně jako operační systém by i databáze měla být zbavena všech zbytečných komponent a udržována v aktuálním stavu. Odstraňte všechny uložené procedury, které nepotřebujete, a deaktivujte všechny nepoužívané služby a uživatelské účty. Vytvořte speciální databázový účet určený výhradně pro přístup z webu a přiřaďte mu pouze minimální požadovaná oprávnění.
V souladu s používáním připravených příkazů se důrazně doporučuje nepoužívat modul mysql PHP (který byl v PHP 7 odstraněn). Místo toho zvolte mysqli nebo PDO, abyste zajistili lepší bezpečnost a kompatibilitu. Bezpečný dotaz mysqli může vypadat takto:
$mysqli = new mysqli("localhost", "username", "password", "database");
if ($mysqli->connect_error) die("Connection failed");
$stmt = $mysqli->prepare("SELECT password FROM users WHERE username = ?");
$stmt->bind_param("s", $_POST['username']);
$stmt->execute();
$stmt->bind_result($hashedPassword);
if ($stmt->fetch() && password_verify($_POST['password'], $hashedPassword)) {
echo "Login successful";
} else {
echo "Invalid login credentials";
}
$stmt->close();
$mysqli->close();phpHesla by nikdy neměla být ukládána přímo do databáze ani načítána v prostém textu. Místo toho použijte hashovací metodu, jako je password_hash(), v kombinaci s password_verify(), abyste bezpečně ochránili přihlašovací údaje. Bezpečná implementace může vypadat takto:
$mysqli = new mysqli("localhost", "username", "password", "database");
$stmt = $mysqli->prepare("SELECT password FROM users WHERE username = ?");
$stmt->bind_param("s", $_POST['username']);
$stmt->execute();
$result = $stmt->get_result();
$row = $result->fetch_assoc();
if ($row && password_verify($_POST['password'], $row['password'])) {
echo "Login successful!";
} else {
echo "Incorrect username or password.";
}phpCo mají bobby tabulky společného s SQL injekcí?
Webová stránka bobby-tables.com používá webový komiks xkcd k vtipnému znázornění nebezpečí nezabezpečených uživatelských vstupů do databází. V komiksu matka přijímá telefonát ze školy svého syna (známého pod přezdívkou Little Bobby Tables). Volající se ptá, zda se její syn opravdu jmenuje Robert'); DROP TABLE Students;--, na což ona odpoví ano. Důvod hovoru je brzy jasný: pokus o zadání jména Robert do studentské databáze způsobil smazání celé studentské tabulky. Matka není příliš soucitná – pouze doufá, že škola se poučila a v budoucnu bude vstupy do databáze kontrolovat.
Komiks jasně poukazuje na katastrofické důsledky, které mohou nastat v případě, že se v databázových aplikacích řádně neověří a nevyčistí uživatelské vstupy.