Artiklar » ASP » DUI-funktion

 
 

DUI-funktion

Författare: mactommy
Datum: den 27 juni 2007
Antal lästa: 3986
Ej stjärnmärkt

Jag känner att jag måste klart och tydligt påpeka att idéen som presenteras bygger på en bra grund, men koden som presenteras innehåller sql injections. Jag lämnar det som en uppgift till läsaren att identifiera dessa, och åtgärda dem. Om ni inte hittar dem, patchar dem och är säkra på att allt är säkert, använd inte denna kod rakt av i applikationer ni bygger. // Tant102

Denna artikel kommer att förklara hur man kan skapa en function som hantera INSERT, UPDATE och DELETE på ett enklare sätt. När man kodar i Microsoft Anteckningar och skapar olika sidor återkommer man alltid till att man har ett formulär som man vill spara ner i en databas. Detta arbete är monotomt, trist och oftast en källa till fel. Jag tänkte här visa hur vi kan skapa en funktion som gör att vi med några enkla medel kan skapa oss en function som vi kan återanvända från sida till sida.

Vi börjar med att skapa oss en tabell i databasen - tblGuestbook. I den vill vi ha några fält att lagra våra gästboksinlägg, vissa är bara för att tydligöra olika fält typer.
fldIndex        Räknare
fldRubrik    Text
fldText        PM
fldNummer    Tal
fldSkribent    Text
fldDatum        Datum/Tid

Observera att jag skriver "fld" framför alla fältnamn och huvudanledningen är för att slippa trilskas med reserverade ord som annars kan ställa till det.

Eftersom vi har våran tabell så ger vi oss på att skapa oss ett formulär: Kod:
<form method="post" action="index.asp">
    Datum: <input type="text" name="datDatum" size="20" /><br/>
    Tal: <input type="text" name="intNummer" size="20" /><br/>
    Text: <input type="text" name="strText" size="20" /><br/>
    <input type="submit" value="Spara" name="#Spara" />
</form>

Här använder jag mig utav namn som är snarlika databasens namn: datDatum - fldDatum, intNummer - fldNummer, strText - fldText. För att veta vad det är för innhåll som ska in i databasen så använder jag mig utav förkortningar på input-rutorna som "str" fär text, "int" för tal och "dat" för datum istället för "fld". Varför mitt namn på submit-knappen börjar på # återkommer jag senare med en förklaring. För att detta ska fungera så är det viktigt att man har ett prefix framför namnet på formuläret och fälten i databasen och att man sedan har samma namn, annars så är det bara sitta och koda som ni tidigare gjort och utan att kunna utnyttja denna funktion.

Nu kan vi börja bygga en funktion som tar emot innehållet ifrån formulären och skapar en SQL-sats som vi kan executa mot databasen Function formExecute(strTable,strType,intIndex,strForm), jag har mitt funktionsnamn formExecute och i det skickar jag in 4st värden. "strTable" som är tabellens namn, "strType" anger om jag ska köra (I)NSERT/(U)PDATE/(D)ELETE och jag anger det med en bokstav, "intIndex" är för att kunna ange ett specifikt index-nummer i databsen och till slut "strForm" som är då hela formuläret som ska fixas till.

För att ha någon möjlighet att använda oss utav både Access och MySQL som databas så anger jag en variabel för att vet aom det är ett # runt datum i Access eller ' runt datum i MySql. Nu använder jag mig utav exempel för en Access-databas för att man ska tydligare se vad som händer.
  strDateSeparator = "#"

Nu börjar det intressanta, vi skickade med en typ-variabel in i våran funktion strType och den använder vi oss utav i en SELECT CASE-sats för att skapa rätt SQL-sats.Kod:
  Select Case UCase(strType)
  Case "D" ' DELETE
  Case "I" ' INSERT
  Case "U" ' UPDATE
  End Select

För att ta bort en post så behöver vi veta vilken tabell och vilket index som skall raderas, dessa har vi med oss in i funktionen och kan därför lätt sätta ihop våran SQL-sats...Kod:
  Select Case UCase(strType)
  Case "D" ' DELETE
    formExecute = "DELETE FROM " & strTable & " WHERE fldIndex = " & CLng(intIndex)
  Case "I" ' INSERT
    ...

Det är väl egentligen inte det mest spännande vi kan göra utan vad som sker när vi kör INSERT och UPDATE. För att loopa igenom alla formulär utan att veta formulärens namn så kan vi använda oss utav For Each strItem In strForm. Detta innebär att vi kommer att få med även knappen's namn och värde när vi loopar ut innhållet ifrån Request.Form. Då kommer trick nummer 1, jag satte in # framför namnet på knappen och kan nu filtrera bort alla delar som inte ska in i databsen, If Left(strItem,1) <> "#" then och på det sättet kan vi enkelt styra vilka delar som skall in i formuläret och vilka vi ska lämna utanför. Trick nummer 2 blir det vi satte framför input-rutorna... str, int och dat... När vi matar in datum i databasen så har vi antingen # eller ' beroende på databas och här har vi då variabeln strDateSeparator, text anger vi med 'text' och tal... så vi kör åter en SELECT CASE-sats för att veta hur variablarna skall in i SLQ-satsen med vilka tecken som omgärdar inmatningen.
Kod:
  Select Case Left(LCase(strItem),3)
  Case "dat"
    strField = strField & "fld" & Mid(strItem,4) & ","
    strValue = strValue & strDateSeparator & CDate(Request.Form(strItem)) & strDateSeparator & ","
  Case "int"
    strField = strField & "fld" & Mid(strItem,4) & ","
    strValue = strValue & CLng(Request.Form(strItem)) & ","
  Case "str"
    strField = strField & "fld" & Mid(strItem,4) & ","
    strValue = strValue & "'" & Replace(Request.Form(strItem),"'","''") & "'" & ","
  End Select

Jag sätter här ihop två variablar strField för namnet och strValue för värdet ifrån formuläret och jag ersätter int, str och dat med fld. När detta är klart skalar jag bort sista kommatecknet med: Kod:
    strField = Left(strField,Len(strField)-1)
    strValue = Left(strValue,Len(strValue)-1)

...och sätter ihop det till våran SQL-sats som skickas åter till våran kod. Kod:
formExecute = "INSERT INTO " & strTable & "(" & strField & ") VALUES (" & strValue & ")"


För UPDATE är det samma sak, men här använder jag bara variabeln strField eftersom jag har fältnamn+innehåll tilsammans. Kod:
  Case "U" ' UPDATE
    ' Loopa igenom alla formulär.
    For Each strItem In strForm
      ' Bortse om det är något formulär-namn som börjar på #
      If Left(strItem,1) <> "#" then
      Select Case Left(LCase(strItem),3)
        Case "dat"
            strField = strField & "fld" & Mid(strItem,4) & "=" & strDateSeparator & CDate(Request.Form(strItem)) & strDateSeparator & ","
        Case "int"
          strField = strField & "fld" & Mid(strItem,4) & "=" & CLng(Request.Form(strItem)) & ","
        Case "str"
          strField = strField & "fld" & Mid(strItem,4) & "=" & "'" & Replace(Request.Form(strItem),"'","''") & "'" & ","
      End Select
      End If
    Next
    strField = Left(strField,Len(strField)-1)
    formExecute = "UPDATE " & strTable & " SET " & strField & " WHERE fldIndex = " & Clng(intIndex)


Hur anropar man då funktinen till sist?Kod:
If Request.Form("#Spara") = "Spara" then
    strSQL = formExecute("tblGuestbook","I",0,Request.Form)
    Connect.Execute (strSQL)
End If

Jag gör ett medvetet val genom att jag hämtar min SQL-sats ifrån funktionen och executar den separat, jag har även möjlighet att låta SQL-satsen executas i min funktion, men... vill vi kontrollera hur SQL-satsen ser ut så kan vi lätt skriva ut varibalen strSQL innan vi executar densamma och har då lätt att felsöka hur det egentligen ser ut med innehållet ifrån formuläret till vår färdiga SQL-sats.

Artiklen ligger som grund för hur man på ett smidig sätt kan uppdatera formulär till en databas med en funktion, dock tar artiklen inte upp alla lömska injectionshål som man kan drabbas utav.

Hela upplägget ser ni här inkl. felhanterare och injection-skydd: http://www.aspsidan.se/code/default.asp?c=7461

Förhoppningsvis så kommer koden på CODE-sidan vara så pass säker att den går att använda i egna applikationer. Jag kommer att prova uppdatera den koden så att man uppnår en hög säkerhets-faktor mot alla ev. tänkbara injection möjligheter. Har jag missat någon injection variant så får ni gärna PM:a mig så att den kan stoppas.

Vilka injection-skydd finns på http://www.aspsidan.se/code/default.asp?c=7461?
1) Replace på ' samt CDate och CLng för inmatade texter ifrån formulären.
2) Formulärnamnen kollas att det inte är några ogiltiga tecken. Formulärnamn kan t.ex. inte innehålla mellanslag, "'" och ";" för att stoppa saker som "DROP TABLE;" eller formulär likt denna: <INPUT TYPE="text" NAME="intAdmin = 1, strUser" VALUE="macTommy">.
3) Möjlighet att utesluta vissa fältnamn att uppdateras/sparas. Har man känsliga fält i tabellen så kan dessa exkluderas för att tas upp i SQL-satsen som genereras ifrån funktionen.
4) Inte fullt så kraftfullt, men HTTP-REFFER koll för att se om formuläret är postat ifrån den egna sidan.


Edit 2007-06-28: Har bytt ut "db"-prefix mot "fld"...
Edit 2007-06-29: Har uppdaterat CODE-sidan med diverse injection-skydd samt möjlighet att ange fält som inte får uppdateras... Uppdaterade lite text i nedersta rutan i artikeln...
 
     

  » Logga in  
 
Användarnamn

Lösenord

 
     

  » Bli medlem  
  Bli medlem på ASPsidan!  
     

     
  Microsoft  
     

  » Partners  
  Comsolvia  
     
  » ANNONS  
  ingen annons än  
     

  » Senast online  
  Endast för inloggade  
  Antal inloggade: 1  
     

Copyright © 2007 www.ASPsidan.se
ingen sponsrar längre ASPsidan med Dedikerad Server
ASPsidan RSS
   
 XHTML / CSS
Det tog 0,0625 sekunder att ladda sidan