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.
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...
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")
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.
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)
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...
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...
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.