Avatar billede lifeweb Nybegynder
12. maj 2008 - 10:24 Der er 14 kommentarer og
1 løsning

Hvordan forhindrer jeg sql-injection

Hej

er der nogen der gider at smide lidt gode råd?
Avatar billede nielle Nybegynder
12. maj 2008 - 10:45 #1
Helt basalt gør du det ved at lave en replace som erstatter '-tegn i dit input med 2 '-tegn. FØR at du putter det i sql-kommandoen:

FY-FY:

navn = Request.QueryString('navn')
sql = "INSERT INTO dinTabel (navn, ...) VALUS ('" & navn & "', ...)"
Conn.Execute(sql)

SÅDAN:

navn = Request.QueryString('navn')
navn = Replace(navn, "'", "''")
sql = "INSERT INTO dinTabel (navn, ...) VALUS ('" & navn & "', ...)"
Conn.Execute(sql)

Dette beskytter mod SQL-injection.
Avatar billede lifeweb Nybegynder
12. maj 2008 - 10:51 #2
tak for et hurtigt svar - er det det eneste?
jeg har hørt at man også skal trimme - men det skader vel ikke at gøre?
Avatar billede frand Nybegynder
12. maj 2008 - 11:55 #3
select * from tabel where felt = ***

du skal forestille dig, hvordan din sql kan komme til at se ud, hvis du ikke validerer ***. Hvad du skal gøre, afhænger af felttypen. Ved f.eks. tal- og datofelter hjælper det ikke at erstatte apostroffer.
Avatar billede lifeweb Nybegynder
12. maj 2008 - 12:03 #4
frand: hva skal man så gøre ved tal og datofelter? og hvad kan der ske i disse tilfælde?
Avatar billede softspot Forsker
12. maj 2008 - 18:20 #5
Du skal til hver en tid validere dine data inden du smider dem efter databasen, så hvis en variabel som f.eks. burde indeholde en dato ikke gør det, skal brugeren have besked om at der er fejl i data og data skal end IKKE forsøges gemt...!

Der findes i øvrigt en anden (og efter min mening bedre) måde at sikre sig mod SQL-injections, nemlig Command-objektet. Den sikrer dels at strenge med skummel SQL ikke "sniges" ind i dit system og der er desuden validering af data ifht. den type du fortæller databasen der skal leveres. Typevalidering er dog ikke en sikring mod at din applikation fejl, den vil bare fejle på en anden måde end hvis du sender ikke valideret data ind i din SQL-streng.

Brugen af Command-objektet er alt lige fra simpel til kompleks alt efter dine behov, så det er noget man bør sætte sig ind i efterhånden som behovet opstår, men min erfaring er, at det dækker behovene igennem en applikation rimeligt bredt. Jeg skal nok lige lægge et eksempel på hvordan det benyttes...
Avatar billede softspot Forsker
12. maj 2008 - 19:49 #6
Som lovet smider jeg lige et eksempel på hvordan du kan bruge Command-objektet. Det tager udgangspunkt i nielle's eksempel (med enkelte syntaktiske rettelser ;-)), så chancen for at du kan se et mønster er større. Jeg har dog indsat en veldefineret feltliste i SQL-sætningen, for at eksemplet bliver mere konkret og færdigt. Desuden har jeg valgt 3 forskellige felttyper for at illustrere hvordan man kan håndtere disse gængse datatyper. Eksemplet er barberet for fejlhåndtering aht. overskueligheden. Det tager sig således ud:

<!-- METADATA TYPE="typelib" uuid="00000205-0000-0010-8000-00AA006D2EA4"  -->
<%
dim navn, dato, antal
dim sql, cmd

navn = Request.QueryString("navn")
dato = Request.QueryString("dato")
antal = Request.QueryString("antal")

sql = "INSERT INTO dinTabel (navn, dato, antal) VALUES (?,?,?)"
set cmd = Server.CreateObject("ADODB.Command")
set cmd.ActiveConnection = conn
cmd.CommandText = sql
cmd.CommandType = adCmdText
cmd.Parameter.Append cmd.CreateParameter("@navn", adVarChar, adParamInput, 50, navn)
cmd.Parameter.Append cmd.CreateParameter("@dato", adDate, adParamInput, 8, dato)
cmd.Parameter.Append cmd.CreateParameter("@antal", adInteger, adParamInput, 4, antal)
cmd.Execute
%>


Den første linie (den med METADATA) sørger for at alle konstanter vedr. ADO (så som adVarChar, adInteger, adDate, adCmdText m.m.fl.) er tilgængelige for sidens kode. Hvis den er inkluderet som vist, kan du bare bruge alle de konstanter som ADO definerer. Du kan med fordel lægge denne METADATA-linie i din global.asa-fil, da du så slipper HELT for at tænke på dette mere. Alle konstanter vil derefter være tilgængelige i hele applikationen! Det vil jeg naturligvis anbefale :)

Det du får ud af denne metode er:

1. du slipper for at bekymre dig om apostroffer i strenge og får dermed lettere ved at validere dine brugeres data, idet du "kun" skal bekymre dig om hvorvidt data er forretningsmæssigt korrekte (hvilket til tider er en stor opgave i sig selv :))

2. du slipper for uoverskuelig SQL-streng sammensætninger, da du får konstante SQL-strenge som er lettere at overskue og som DU har kontrol over (ikke brugeren)

3. i tilfælde af typefejl på værdier til parametre, rejses fejl på et tidligere tidspunkt end hvis du sender en forkert type værdi til databasen

4. du får en mere strømlinet kode som er lettere at vedligeholde

Ulemperne:

Well, det performer nok lidt dårligere end en direkte execute på connection-objektet, men i en opdateringssituation vil jeg mene det er til at overskue. Jeg har ikke selv testet det, så jeg ved ikke hvor stor forskellen er, men jeg vil i langt de fleste tilfælde foretrække at tage denne ulempe med de gevinster jeg ser. Dog vil jeg mene at metoden er mest relevant i de tilfælde hvor du forespørger/opdaterer databasen med data som brugeren har indtastet, da det er her risikoen for injection typisk er størst. Det betyder at jeg vil hver en tid vil foretrække følgende:

set rs = conn.execute("SELECT COUNT(*) FROM tabel")

frem for:

set cmd = Server.CreateObject("ADODB.Command")
set cmd.ActiveConnection = conn
cmd.CommandText = "SELECT COUNT(*) FROM tabel"
cmd.CommandType = adCmdText
set rs = cmd.Execute

Da der ikke er nogen brugerangivede data involveret i forespørgslen. Ligeledes ville jeg til denne SQL også vælge den direkte connection-baserede execute frem for Command-objektet:

conn.execute "UPDATE besoegstaeller SET antal = antal + 1"

da der ikke er nogen form for brugerangivede data involveret og det hele kan klares med databasens egne funktioner.
Avatar billede nielle Nybegynder
17. juni 2008 - 06:30 #7
Har du fået svar på dit spørgsmål?
Avatar billede lifeweb Nybegynder
17. juni 2008 - 12:08 #8
jeg fandt faktisk på noget endnu bedre...
sql injections sker jo via variabler sendt via post eller get...
derfor har jeg lavet en lille funktion til alle connection-filer, hvori jeg løber samtlige variabler igennem for ulovlige ord (declare osv)

det virker supergodt!
Avatar billede lifeweb Nybegynder
17. juni 2008 - 12:08 #9
i må gerne smide nogle svar, hvis i vil have point - jeres ting er jo også rigtige :)
Avatar billede softspot Forsker
17. juni 2008 - 12:47 #10
Command-objektet er generisk og der er ikke nogen restriktioner på hvilket indhold du kan smide i din database. Din egen metode forhindrer, såvidt jeg kan forstå, jo en del indhold, hvis du, via din filtreringsfunktion, vil undgå alt hvad der minder om SQL...
Avatar billede softspot Forsker
17. juni 2008 - 13:21 #11
Tak for point (selvom jeg havde forventet at nielle også skulle have haft en slat) :)
Avatar billede lifeweb Nybegynder
17. juni 2008 - 13:25 #12
arh crap... nielle vil du ha point?
Avatar billede nielle Nybegynder
17. juni 2008 - 17:34 #13
Det er for sent nu. :^)

Det er vist i øvrigt ikke tilstrækkeligt at tjekke for "forbudte ord" hvis man vil beskytte sig 100 %.
Avatar billede lifeweb Nybegynder
17. juni 2008 - 17:43 #14
det er skam ikke for sent, jeg opretter gerne et spørgsmål så du kan få nogle point ;)

hvad skal der yderligere til?
pt. tjekker jeg for en masse ord, validerer om det er tal eller bogstaver og banner brugeren hvis der er noget der virker mystisk...

det du skriver i dit første indlæg sørger min funktion også for...
Avatar billede jespernerd Nybegynder
18. november 2008 - 03:27 #15
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester