Hva er en SQL-injeksjon?
SQL-injeksjoner utgjør en betydelig trussel mot relasjonsdatabasemodeller og den sensitive informasjonen de inneholder. Derfor er det helt avgjørende med omfattende beskyttelse mot slike uautoriserte forsøk på ekstern tilgang – som muliggjøres av sikkerhetshull.
Hva er en SQL-injeksjon?
En SQL-injeksjon er en type angrep som utnytter en sikkerhetshull i relasjonsdatabasesystemer som bruker SQL-språket til å behandle brukerinnspill. Angriperen utnytter brukerinndata som ikke er riktig eskapet og som inneholder spesialtegn som doble bindestreker, anførselstegn eller semikolon. Disse tegnene har spesielle funksjoner for SQL-tolken og gjør det mulig å manipulere kommandoene som utføres eksternt. SQL-injeksjoner er ofte forbundet med PHP- og ASP-applikasjoner som er avhengige av utdaterte grensesnitt. I mange av disse tilfellene blir ikke inndataene renset tilstrekkelig, noe som gjør dem til et primært mål for angrep.
Ved å plassere funksjonstegn på strategiske steder kan en uautorisert bruker innføre ekstra SQL-kommandoer og manipulere databaseoppføringer for å lese, endre eller slette data. I alvorlige tilfeller kan angripere til og med få tilgang til systemets kommandolinje, noe som kan gi dem full kontroll over databaseserveren.
Eksempel på SQL-injeksjon som viser hvordan et databaseangrep fungerer
Siden sårbare databaseservere raskt kan identifiseres og SQL-injeksjonsangrep er relativt enkle å gjennomføre, er denne metoden fortsatt en av de mest brukte teknikkene blant nettkriminelle over hele verden. Angripere benytter ulike strategier og utnytter både nyoppdagede og velkjente sikkerhetshull i applikasjonene som inngår i datahåndteringsprosessen. For å bedre forstå hvordan SQL-injeksjon fungerer i praksis, skal vi se på to vanlige angrepsmetoder som eksempler.
Eksempel 1: Tilgang via brukerinndata med mangelfull eskaping
For å få tilgang til en database må brukerne vanligvis logge seg på først. Til dette formålet brukes det ofte skript for å vise et påloggingsskjema med felt for brukernavn og passord. Brukerne fyller ut skjemaet, og skriptet sjekker deretter om det finnes samsvarende oppføringer i databasen. Som standard kan databasen inneholde en tabell med users med kolonnene username og password. I en typisk webapplikasjon kan de relevante skriptlinjene for databasetilgang (ved bruk av Python-lignende pseudokode) se slik ut:
uname = request.POST['username']
passwd = request.POST['password']
sql = "SELECT id FROM users WHERE username='" + uname + "' AND password='" + passwd + "'"
database.execute(sql)pythonEn angriper kan nå manipulere passordfeltet ved hjelp av en SQL-injeksjon, for eksempel ved å skrive inn password' OR 1='1, noe som resulterer i følgende SQL-spørring:
sql = "SELECT id FROM users WHERE username='' AND password='password' OR 1='1'"pythonDette gir angriperen full tilgang til hele brukertabellen i databasen, siden passordbetingelsen alltid gir resultatet «sant» (1='1'). Hvis angriperen logger seg på som administrator, kan vedkommende fritt endre alle oppføringene i databasen. Alternativt kan feltet for brukernavn manipuleres på samme måte.
Eksempel 2: Datauttrekk ved hjelp av ID-manipulering
Å hente informasjon fra en database ved hjelp av en ID er en praktisk og vanlig metode, men åpner også for muligheten for SQL-injeksjon. For eksempel vet en webserver, gjennom en ID som sendes med i en URL, hvilken informasjon den skal hente fra databasen. Det tilhørende PHP-skriptet ser slik ut:
<?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);
}
?>phpDen forventede URL-adressen følger mønsteret .../script.php?id=22. I dette tilfellet vil tabelloppføringen med ID «22» hentes. Hvis en uautorisert person får mulighet til å manipulere denne URL-adressen og i stedet sender en forespørsel som .../script.php?id=22+OR+1=1, vil den resulterende forespørselen føre til at alle rader i tabellen hentes:
SELECT * FROM table WHERE id=22 OR 1=1;sqlHvordan finner kriminelle sårbare databasesystemer?
I prinsippet kan ethvert nettsted eller enhver nettapplikasjon som bruker SQL-databaser uten forhåndsdefinerte spørsmål (prepared statements) eller andre beskyttende tiltak, være sårbar for SQL-injeksjoner. Sårbarheter som oppdages, forblir ikke skjult lenge på internett. Det finnes faktisk nettsteder som publiserer oppdaterte lister over kjente sikkerhetshull – og til og med forklarer hvordan angripere kan bruke Google-søk for å finne relevante nettprosjekter. Hvis et nettsted returnerer detaljerte SQL-feilmeldinger, kan nettkriminelle bruke disse meldingene til å identifisere potensielle sårbarheter. For eksempel kan det å legge til en apostrof på slutten av en URL som inneholder en ID-parameter allerede avsløre en svakhet, som vist i følgende eksempel:
[DomainName].com/news.php?id=5’Et sårbart nettsted sender tilbake en feilmelding i følgende form:
Query failed: You have an error in your SQL syntax…
Lignende metoder kan også brukes til å hente ut antall kolonner, tabell- og kolonnenavn, SQL-versjonen eller til og med brukernavn og passord. I tillegg finnes det ulike verktøy som kan automatisere både kartleggingsprosessen og gjennomføringen av SQL-injeksjonsangrep.
Slik beskytter du databasen din mot SQL-injeksjon
Det finnes flere ulike metoder du kan bruke for å forhindre SQL-injeksjonsangrep på databasesystemet ditt. Du bør ta hensyn til alle de involverte komponentene – både serveren, de enkelte applikasjonene og databasestyringssystemet.
Trinn 1: Overvåk automatiske innspill fra applikasjoner
Når man behandler data fra eksterne eller innebygde applikasjoner, er det avgjørende å validere og filtrere de innsendte verdiene for å forhindre SQL-injeksjoner.
1. Valider datatyper
Hvert inndatafelt må samsvare med den forventede datatypen. Hvis det for eksempel kreves et numerisk inndatafelt, kan en enkel validering i PHP se slik ut:
if (filter_var($input, FILTER_VALIDATE_INT) === false) {
throw new InvalidArgumentException("Invalid input");
}phpTilsvarende kontroller bør innføres for tekststrenger, datoer eller andre spesifikke formater.
2. Filtrer spesialtegn
Spesialtegn kan utgjøre en sikkerhetsrisiko, særlig i SQL- eller HTML-sammenheng. En sikker fremgangsmåte er å bruke htmlspecialchars() for HTML-inndata og PDO::quote() for SQL-spørsmål.
3. Unngå å vise feilmeldinger
Direkte feilmeldinger som avslører tekniske detaljer om databasen eller systemet, bør unngås. Vis i stedet en generell melding som for eksempel:
echo "An error occurred. Please try again later.";
error_log("Unexpected error encountered. See system log for details.");php4. Bruk forhåndsdefinerte setninger
En av de mest effektive måtene å forhindre SQL-injeksjoner på er å bruke forhåndsdefinerte setninger. Ved denne metoden sendes SQL-kommandoer og parametere separat, slik at skadelig kode ikke kan kjøres. Her er et eksempel på implementering i PHP ved hjelp av PDO (PHP Data Objects):
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->bindParam(':id', $user_id, PDO::PARAM_INT);
$stmt->execute();phpDatabasestyringssystemet sørger automatisk for at innlegget behandles på en sikker måte.
Trinn 2: Sørg for omfattende serverbeskyttelse
Sikkerheten til serveren som databasestyringssystemet ditt kjører på, spiller også en avgjørende rolle i forebygging av SQL-injeksjon. Et viktig tiltak er å sikre operativsystemet ved å følge disse anbefalte fremgangsmåtene:
- Installer eller aktiver kun de programmene og tjenestene som er nødvendige for å kjøre databasen.
- Fjern alle ubrukte eller unødvendige brukerkontoer.
- Sørg for at alle relevante system- og programvareoppdateringer installeres umiddelbart.
- Bruk prinsippet om minst mulig privilegier for å sikre at brukere og tjenester kun tildeles de minimale tillatelsene som er nødvendige.
Avhengig av sikkerhetskravene til nettprosjektet ditt, bør du vurdere å iverksette ytterligere sikkerhetstiltak:
- Systemer for inntrengingsdeteksjon (IDS) og systemer for inntrengingsforebygging (IPS): Disse systemene bruker ulike deteksjonsmetoder for å oppdage angrep på et tidlig stadium, utløse varsler og – ved bruk av IPS – automatisk iverksette mottiltak.
- Application Layer Gateway (ALG): En ALG overvåker og filtrerer trafikk mellom applikasjoner og nettlesere direkte på applikasjonsnivå.
- Web Application Firewall (WAF): En WAF beskytter spesielt webapplikasjoner mot SQL-injeksjon og Cross-Site Scripting (XSS) ved å blokkere eller rense mistenkelige forespørsler.
- Zero Trust-tilnærming: Denne moderne sikkerhetsmodellen sikrer at hvert tilgangsforsøk – uavhengig av opprinnelse – blir verifisert og autentisert før tilgang gis.
- Brannmurregler og nettverkssegmentering: Disse er avgjørende for å minimere angrepsflaten på lang sikt.
- Regelmessige IT-sikkerhetsrevisjoner og penetrasjonstester: Disse bidrar til å oppdage og fikse sårbarheter på et tidlig stadium.
Trinn 3: Sikre databasen og bruk sikker kode
Akkurat som operativsystemet ditt bør databasen din ryddes for alle unødvendige komponenter og holdes oppdatert. Fjern alle lagrede prosedyrer du ikke trenger, og deaktiver alle tjenester og brukerkontoer som ikke er i bruk. Opprett en egen databasekonto som kun er beregnet på nettilgang, og tildel den kun de minimumsrettighetene som er nødvendige.
I tråd med bruken av forhåndsdefinerte setninger anbefales det på det sterkeste å ikke bruke mysql PHP-modulen (som ble fjernet i PHP 7). Velg i stedet mysqli eller PDO for å sikre bedre sikkerhet og kompatibilitet. En sikker mysqli kan se slik ut:
$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();phpPassord bør aldri lagres direkte i en database eller hentes frem i ren tekst. Bruk i stedet en hashingmetode som password_hash() i kombinasjon med password_verify() for å sikre påloggingsopplysningene. En sikker implementering kan se slik ut:
$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.";
}phpHva har bobbybord med SQL-injeksjon å gjøre?
Nettstedet bobby-tables.com bruker en xkcd-netttegneserie til på en humoristisk måte å illustrere farene ved usikre brukeropplysninger i databaser. I tegneserien mottar en mor en telefon fra skolen til sønnen sin (kjent under kallenavnet «Little Bobby Tables»). Den som ringer spør om sønnen hennes virkelig heter Robert'); DROP TABLE Students;--, noe hun bekrefter. Årsaken til samtalen blir snart klar: forsøket på å legge inn Robert i elevdatabasen førte til at hele elevtabellen ble slettet. Moren er ikke særlig forståelsesfull – hun håper bare at skolen har lært sin lekse og vil rense databaseinngangene fremover.
Tegneserien viser tydelig de katastrofale konsekvensene som kan oppstå hvis man ikke validerer og renser brukerinnspill på riktig måte i databaseapplikasjoner.