freestone-carryout
freestone-carryout
freestone-carryout
freestone-carryout

Vad är en SQL-injektion?

En webbapplikation är sårbar för SQL-injektion då icke-validerad indata används för att bygga upp en SQL-sats. Antag att parametrarna "username" och "password" inte valideras i metoden "loginUser" (se kodexempel nedan). En användare kan då ange "' or '1'='1" i lösenordsfältet vilket ger följande SQL-sats (indata från lösenordsfältet är markerat i fet stil): select * from user_login where user='hubba' and pwd='' or '1'='1';

Denna SQL-sats returnerar aldrig ett tomt "result set" varför "loginUser" alltid returnerar "true". Angriparen har således kommit förbi autentiseringen. Eftersom SQL är uttrycksfullt är denna typ av sårbarhet allvarlig. Exempelvis kan angriparen utföra CRUD-operationer (Create, Read, Update, Delete), läsa meta-data eller anropa "stored procedures" vilka kan ha kopplingar till operativsystemet. För att skapa en applikationsanvändare i vårt exempel kan följande anges (";" terminerar en SQL-sats och "--" inleder kommentar):

  • select * from user_login where user='hubba' and pwd=''; insert into user_login values ('99', 'lucifer', 'dfgGSba71X_'); --';

// -- Sårbar Java-kod --
public boolean loginUser(Connection dbConn, String username, String password) throws SqlException {
String sql = "select * from user_login where user='" + username + "' and pwd='" + password + "'";
Statement stmt = dbConn.createStatement();
try {
return stmt.executeQuery(sql).next();
} finally {
stmt.close();
}
}


Lösningen på problemet är att aldrig konkatenera ihop en SQL-sats utan parametrisera den. Det går att göra i de flesta programmeringsspråk. Så här ser det ut i Java:

// -- Säker Java-kod --
public boolean loginUser(Connection dbConn, String username, String password) throws SqlException {
String sql = "select * from user_login where username=? and password=?";
PreparedStatement stmt = dbConn.prepareStatement(sql);
stmt.setString(1, username);
stmt.setString(2, password);
try {
return stmt.executeQuery().next();
} finally {
stmt.close();
}
}

Webbplatser baserade på ASP har varit mest drabbade av automatiserade attacker. Här att ett exempel i ASP:

' -- Sårbar ASP-kod --
' Assume that objConn holds connection to db.
strCmd = "select user_id, user_name from users where user_name='" + strUserName + "' AND password='" + strPassword + "'"
Set objCommand.ActiveConnection = objConn
objCommand.CommandText = strCmd
objCommand.CommandType = adCmdText
Set objRS = objCommand.Execute()
' Process the resultset

Problemet är att SQL-satsen konkateneras ihop med indata, precis som i Java-exemplet. Lösningen är densamma, nämligen att parametrisera SQL-satsen genom att använda "CreateParameter" och "Parameters.Append".


' -- Säker ASP-kod --
' Assume that objConn holds connection to db.
strCmd = "select user_id, user_name from users where user_name=? AND password=?"
Set objCommand.ActiveConnection = objConn
objCommand.CommandText = strCmd
objCommand.CommandType = adCmdText
Set param1 = objCommand.CreateParameter ("user", adWChar, adParamInput, 20)
param1.value = strUserName
objCommand.Parameters.Append param1
Set param2 = objCommand.CreateParameter ("password", adWChar, adParamInput, 50)
param1.value = strPassword
objCommand.Parameters.Append param2
Set objRS = objCommand.Execute()
' Process the resultset

Skydd mot SQL-injektion

Följande kan göras för att skydda sig då applikationen utvecklas:

  • Använd parametrisera SQL-satser. Bygg aldrig ihop en SQL-sats med indata. Se ovan för kodexempel.
  • Sanitetskontrollera och validera indata. All indata ska behandlas som ond! Använd ett klassbibliotek för validering av strängfält, datum, heltal, e-postadresser med mera. Viktigt är att valideringen inte sprids ut i koden, utan samlas på ett ställe. JavaScript-validering i klienten kan förhöja användbarheten men går inte att förlita sig på ur ett säkerhetsperspektiv. All indata måste valideras igen på servern eftersom en angripare lätt kan manipulera ett HTTP-anrop. Var restriktiv där det går, undvik exempelvis [<, >, ", #, --, ;, %, ?, @] i ett förnamnsfält. I vissa fall måste "farliga" tecken tillåtas, exempelvis kan citationstecken och "enkelfnutt" förekomma i kommentarsfält.
  • Anropa enbart "Stored Procedures" (SP). För att öka skiktningen kan alla SQL-satser i applikationen innehålla anrop till en SP istället för exempelvis en "select"-sats. Fördelen är att applikationen arbetar mot ett väl definierat gränssnitt, och det underliggande databasschemat kan ändras utan att gränssnittet och därmed applikationen påverkas. Lösningen ger även säkerhetsmässiga fördelar då det är mer naturlig att parametrisera SP-kod. Observera dock att det ingen garanti, eftersom det även i en SP går att konkatenera ihop SQL-satser. En annan fördel med skiktningen är att all SQL-kod samlas på ett och samma ställe, vilket underlättar kodgranskning.
  • Kodgranskning. Det finns två typer av kodgranskning:
    • Manuell: En utvecklare går igenom någon annans kod för att hitta buggar och säkerhetshål. Nyttigt och lärorikt om det görs kontinuerligt i utvecklingsteamet. För att leta efter SQL-injektionshål kan koden genomsökas efter förekomster av exempelvis "executeQuery()" (Java), "Execute()" i "ADODB.Command"-klassen (ASP) eller "Open()" i "ADODB.RecordSet"-klassen (ASP). En modern IDE underlättar arbetet, där det går att söka på exempelvis "alla anrop till denna metod" istället för rena textsökningar.
    • Automatiserad: En applikation går igenom källkoden och utför en statisk analys av den. MSCASI (Microsoft Source Code Analyzer for SQL Injection) är ett gratisverktyg som letar efter SQL-injektionsproblem i ASP-kod. För Java finns liknande verktyg, exempelvis Findbugs som är mycket användbar för generell analys. Findbugs är öppen källkod och är även integrerad i en kommersiell produkt som är mer inriktad på att hitta säkerhetsrelaterade buggar.
  • Automatiserade testverktyg. Denna typ av verktyg letar efter säkerhetshål genom att "spindla" applikationen för att ta reda på potentiellt sårbara sidor, och skickar sedan specialkonstruerade HTTP-anrop till dessa sidor. Microsoft har tillsammans med HP tagit fram verktyget Scrawlr som finns i en nerbantad gratisversion. Sqlmap är ett annat alternativ baserat på öppen källkod. Denna typ av verktyg är inte språkspecifika, exempelvis kan Sqlmap användas för att testa både Java- och ASP-applikationer. Samtidigt är vissa typer av sårbarheter knutna till plattformen, varför vissa testverktyg lämpar sig bättre än andra till en specifik applikation. Verktygen är också olika duktiga på olika typer av SQL-injektion. Att använda flera verktyg kan därför vara en bra lösning.
  • Logga. Vettig loggning i applikationen kan vara till stor hjälp vid en incident. Loggning förhindrar inte en SQL-injektion, men loggarna kan avslöja vilken del av koden som är sårbar.


Följande kan göras för att skydda en befintlig applikation:

  • Databasanvändare med begränsade privilegier. Webbapplikationen ska använda en egen användare i databasen med så få privilegier som möjligt. Använd aldrig "sa"-användaren eller motsvarande.
  • Applikationsbrandvägg. En applikationsbrandvägg fungerar som ett filter. Om URL:en innehåller en misstänkt SQL-injektion omdirigeras besökaren till en felsida. För Apache finns mod_security. Microsoft erbjuder gratis programmet UrlScan. Tyvärr är UrlScan 2.5 för primitiv för att skydda effektivt mot SQL-injektionsattacker eftersom det inte går att filtrera på "query"-delen av URL:en (dvs. allt efter "?"). Den nya versionen, UrlScan v3.0 Beta, är mer kraftfull och tillåter filtrering på "query strings". Tänk på att testa filtret ordentligt innan det tas i produktion. Blockas de URL:er som ska blockas? Håll koll på loggarna eftersom det finns risk att legitim trafik filtreras bort. De finns en rad kommersiella alternativ till UrlScan som ofta innehåller fler funktioner.
  • Övervaka webbserverns loggarna. Använd ett övervakningsprogram, exempelvis OSSEC, för att upptäcka möjliga attacker. Liksom applikationsloggar är webbserverns loggar vara värdefulla vid en incident.
  • En IDS (Intrusion Detection System), till exempel Snort, som lyssnar på trafiken till webbservern på paketnivå och varnar vid potentiella attacker är också ett värdefullt skydd. En IDS upptäcker endast angrepp medan en IPS (Intrusion Prevention System) även kan förhinda angrepp då den blockerar otillåten trafik.
Gunnar Sträng använde både hängslen och livrem, och satte dessutom fast sin plånbok i fickan med en säkerhetsnål. Han visste att god säkerhet bygger på många lager. Förlita dig inte på en metod eller ett verktyg, utan använd alltid flera.

Avslutningsvis vill vi tipsa om WebGoat, vilket är en applikation full av säkerhetshål gjorda med flit. Genom att exprimentera runt i applikationen fås en bra förståelse för hur en SQL-injektion fungerar.

0 kommentarer