SQL Programmering: Sikker programudvikling

SQL Programmering: Sikker programudvikling

SQL Programmering: Sikker programudvikling

Hvordan sikrer du, at din kode bliver sikker? Vi hjælper dig på vej

Vi har tidligere på disse sider skrevet om forskellige metodikker til, hvordan man kan udvikle sikker kode. Men vi er endnu ikke kommet med konkrete eksempler på, hvad sikker kode vil sige. Det råder vi bod på i denne samt en efterfølgende artikel.

I denne første del vil vi have fokus på SQL injection. Den næste artikel, som du kan læse i Alt om DATA nr. 4 2017, vil fokusere på de ting, man skal være opmærksom på, når man koder i f.eks. C/C++. Men vi starter som lovet med et kig på SQL injection og dennes sårbarheder.

Angreb med SQL injection

SQL injection er og har været i mange år en kernedel af en angribers våbenarsenal. Vi hører til stadighed om, at mange indbrud hos selv store virksomheder er baseret på et SQL injection-angreb. Men hvad er et SQL injection-angreb, og hvad består det af? Lad os starte med at kigge på et eksempel.

Tag et kig på figur 1.

Figur 1

Her har vi konstrueret en tekststreng, som har til formål at skulle bruges som en forespørgsel til databasen. Selve forespørgslen vil fungere, men hvis du kender til ASP.NET-programmering, så vil du lægge mærke til, at vi har brugt tekstværdierne fra input-boksene direkte i SQL-strengen. Det er en rigtig dårlig ide, da jeg ikke kan vide, hvad brugeren i den anden ende skriver ind i mine tekstbokse.

Hvis nu en snedig bruger skriver ’OR 0=0’, ind i de to tekstbokse, så vil min SQL-streng pludseligt se ud som på figur 2.

Figur 2

Nu har jeg pludselig en tekststreng, som vil logge brugeren ind uden et brugernavn eller et password, hvis den bliver eksekveret af en database.

Ved at skrive ’OR 0=0’ i tekstboksene, har brugeren lavet en tekststreng, som altid vil være sand, forstået på den måde, at når en database ser en option, der siger ’OR 0=0’, så ser den en option, der altid vil være sand. 0 er altid lig med 0, og ved at bruge ’OR’-option i SQL, så vil hele den del, der omhandler UserName og PassWord være sande.

Voila, en fuldstændig ukendt bruger er nu logget ind på systemet. Nu har vi brugt brugernavn og password i dette eksempel, men det samme gør sig gældende for alle andre SQL queries, som bliver opbygget dynamisk af systemet på baggrund af, hvad en bruger skriver i forskellige input-bokse.

Der findes et utal af forskellige SQL injection-sårbarheder ude på det grumme internet.

Jeg har vist, hvordan en bruger kan logge ind uden et brugernavn og et password, men der er andre måder en angriber kan forårsage kaos på et system, der har adgang til internettet.

Hvad siger du til et angreb, som sletter en eller flere af de tabeller, du har i din database? I dette tilfælde er der tale om et angreb, som kan udføres af en legitim bruger! Kig på figur 3.

Figur 3

Hvis en bruger skriver: ’110 ; DROP TABLE Payroll’, ind i tekstboksen, så vil vores SQL-streng pludseligt se ud som på figur 4.

Figur 4

Ved at bruge et semikolon efter UserID, så er min tekststreng pludselig blevet til en batch query.

En batch query vil sige, at den SQL, der er før semikolon, vil blive eksekveret først fulgt af den SQL, der kommer efter semikolon, og som sletter min Payroll tabel. Begge de situationer, vi har brugt som eksempler, er slemme. Som sagt findes der mange andre eksempler på SQL injections, og er du udvikler, så er det værd at sætte dig ind i de metoder, der står bag dem, så du kan beskytte din applikation imod dem.

Beskyttelse mod SQL injections

Men hvordan beskytter du imod dem? Validering, validering, validering. Validering alle vegne, på klienten, på serveren og hvis du også kan – på databaseserveren. Man kan selvfølgelig bruge et ORM-system, som f.eks. Entity Framework eller NHibernate på en Microsoft-platform, det vil skaffe langt de fleste SQL injections af vejen.

Der findes tilsvarende systemer til Java og mange andre programmeringssprog, så hvis du udvikler på en anden platform, så er det værd at undersøge, hvad mulighederne er for dit system! Det eksempel, vi her vil præsentere for at modvirke SQL injections, er baseret på .NET, simpelthen, da det er den platform, vi er mest kendt med. Eksemplet forudsætter, at man ikke har valgt at bruge Entity Framework eller en anden ORM-platform til at tilgå den underliggende database.

Vi har set, at det at bruge data direkte fra en tekstboks ikke er nogen god ide, og vi ved, at vi skal validere den data, der bliver returneret fra klienten til serveren. Eksemplet bruger SQL-parametre fra ADO.NET. Kig på figur 5.

Figur 5

Her har vi forvandlet UserID til et SQL-parameter i vores tekststreng. Ved at forvandle den til et SQL-parameter, kan vi specificere, hvad det er for en datatype, vi forventer, at den skal have, i dette tilfælde en integer datatype, altså et heltal.

Ved at gøre det på denne måde kan en bruger ikke længere skrive en tekststreng ind i inputfeltet, og ad den vej evt. slette en tabel, simpelthen fordi det vil fejle på databasen. Ved at bruge SQL-parametre kan du sikre dig, at det er de rigtige datatyper, der bliver sendt videre til databasen. Det står og falder naturligvis med, om databasen bruger disse datatyper i tabellerne.

Hvis det hele er sat op som tekststrenge, så er dette eksempel ikke en mulighed. Har du en database, hvor dette er situationen, så ville vi stærkt overveje, om ikke det var på sin plads at restrukturere den. Alt afhængig af hvordan man har valgt at strukturere koden i din virksomhed, så vil denne metode være vejen frem, eller I kan ændre jeres set-up til at bruge Store Procedures i stedet for. På den måde kan I flytte valideringen til databaseserveren. Det vigtige er, at man aldrig skal stole på det input, man får tilsendt fra klienten til serveren, og altid validere denne data.