18. november 2008 - 12:43Der er
29 kommentarer og 1 løsning
Sikkerhed når der skrives til database
Hej eksperter,
Jeg sidder og skal have styr på sikkerheden når man lagrer ting i en database, nærmere når ASP bruges til at lagre ting i en access mdb database.
Eksempel nedenstående er vel den simple måde at få tilgang til en database: <% ' ADODB connection objektet Set Conn = Server.CreateObject("ADODB.Connection") ' Husk at angive den rigtige sti til din database DSN = "DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=" & Server.MapPath("/cgi-bin/database.mdb") ' Åben databaseforbindelsen Conn.Open DSN %>
og igen lukker:
<% ' Luk databaseforbindelse Conn.Close Set Conn = Nothing %>
Hvordan opstår der sikkerhedshuller med den slags type at komme til db'en? Hvordan forhindrer det ? Og hvad bruger eks. store banksites, som måske er de sværeste at hacke sig ind på?
Teknologi, AI og forretning er i centrum på Computerworlds Cloud og AI Festival i København d. 18. og 19. september. Se hele programmet for den store konference om strategisk brug af Cloud og AI på: www.cloud-festival.dk
normalt skyldes sikkerhedshuller ikke connectionen til databasen men derimod i talen med selve dataene - du bliver nødt til at have en connection så der er ikke så meget at ændre (udover at man kunne sætte password, bruge en rigtig database og sikre miljøet i og omkring databasen (fx firewall). Sikkerhed omkring dette er et stort og bredt område og der skal nok mere en server-haj ind over det emne.
Som nævnt ligger de fleste sikkerheds-issues i kommunikationen med dataene på databasen - ikke mindst selvfølgelig hvad man giver brugerne værktøjer til men det er selvfølgelig et spørgsmål og firmapolitik og rettigheder, det vigtigste som programmør er helt klart at sikre imod SQL-injections, se fx http://web-dev.dk/post/2008/07/SQL-injections---mere-end-bare-et-pling.aspx
Set Rs = Server.CreateObject("ADODB.Recordset") Rs.Open "TabelNavn", Conn, 2, 2 Rs.AddNew Rs("EnInt") = 1 Rs("enDato") = date Rs("EnFloat") = 1500.50 Rs("EnTekst") = "Hej med dig O'Connell" Rs.Update Rs.close
Hvis du kender lidt til ASP og database indsættelse, kender du også til problemerne med datoer, single ping (') og kommatal. Med denne metode er disse problemer ikke tilstede.
Nå, nu kom keysersoze lige med en god artikkel, men jeg smidder lige dette aligevel. Har jo brugt tid på at skrive det :)
Nej, denne metode er automatisk sikret mod SQL injections. Den er også sikret mod dato format problemet. Access godtager f.eks kun "mm-dd-yyyy" (bemærk dd og mm er omvendt) formatet via inserts.
Lad os antage at en bruger indsætter 1 feb (altså "01-02-2008") i en input boks: conn.execute("insert into enTabel(enDato) values(#"& request.form("dato") &"#)")
Dette vil Access opfatte som den 2 jan da "01" er måneden og "02" er dagen ifølge dens logik. Med AddNew metoden sikre ASP automatisk at formatet er rigtigt, samt den også sikre mod single ping (').
det er specielt brugerinput - deriblandt input fra forms og querystrings - du skal sikre imod misbrug. Hvis du kun hardcodede data ind i databasen som i fennecs første eksempel var det ikke noget problem - det er brugerne der er problemet :)
Det er meget meget vigtigt at du sikrer dig mod sql injections - benytter du access er risikoen ikke så stor som ved andre databaser da access ikke kan arbejde med multiple statements men det skal selvfølgelig stadig sikres.
så længe databasen ligger et sikret sted - fx en mappe uden for webscope - bør du med access ikke foretage dig noget ydeligere.
s0mmer >> Så du er rigemelig ny inden for ASP og databaser :)
RS variablen er et recordset objekt (lige som din conn er et connection objekt). Et recordset indeholder de data som kommer fra en database, men kan også kommunikere tilbage igen (via update og addNew)
Conn er din database forbindelse (har du selv lave koden til): ' ADODB connection objektet Set Conn = Server.CreateObject("ADODB.Connection") ' Husk at angive den rigtige sti til din database DSN = "DRIVER={Microsoft Access Driver (*.mdb)}; DBQ=" & Server.MapPath("/cgi-bin/database.mdb") ' Åben databaseforbindelsen Conn.Open DSN
2, 2 er CursorType og LockType. Det er det som angiver om man må skrive til databasen eller om man kun må læse. Samt om man må hoppe frem og tilbage i rækkerne eller kun gå frem. http://msdn.microsoft.com/en-us/library/ms675544(VS.85).aspx
Når du henter data fra en database kan du derfor sætte den til "read only". Så er der lidt ekstra sikkerhed :)
webscope er det som kan ses fra internettet. ASP kan hente informationer uden for webscope. Din hjemmeside ligger f.eks i c:\websitets\etSite\ mappen, men din database kan sagtens ligge i c:\minDatabase.mdb. Havde du den liggende inden i "etSite" mappen, ville man kunne downloade den via din hjemmeside.
Nej, det kan den ikke. Det er netop derfor at den skal være uden for webscope :) Normalt har ASP udbydere en DB mappe, som ligger uden for webscope.
Deres opbygning er normalt noget ala dette: d:\websitets\kundeSite.dk\DB\ d:\websitets\kundeSite.dk\wwwRoot\
Webfilerne skal derfor ligge i wwwRoot folderen, og da det er webroden, kan man ikke komme til DB mappen fra internettet. Databasen er derfor helt skjult, men ASP kan sagtens komme uden for webroden og kan derfor godt hente data fra DB mappen.
Hvis man selv hoster sitet, kan man dog sætte IIS'en op til ikke at tillade download af databasen, selv om den ligger inden for webscope.
fennec > Jeg suger alt info'en til mig.. og takker mange gange. 2 sidste (nemme) spørgsmål. jeg skal teste at din metode rent faktisk virker.
Så 1: Kan jeg få et eksempel på en SQL injection i en "opret bruger" ala side. Er det muligt at bare indsætte ;DELETE * FROM userData i eksempel det ønskede brugernavn så alle brugere slettes?
og 2: På min "gamle" metode som ikke tager højde for SQL injections prøver jeg at indsætte flere værdier i db med: strSQL = "Insert into userData (username,password) values('hej1','hej2')" men så snart jeg tager ,password og ,'hej2' med så virker det ikke. hvorfor?
Lige netop Access kan ikke arbejde med "multiple statements", så her er det ikke muligt via insert/update/select at slette hele tabeller. Men derfor kan man lige så godt beskytte sig imod det alligevel. Kunne jo være man migrerede til MS-SQL eller MySQL på et tidspunkt.
Det eneste du skal være bekymret for med Access er f.eks login siden.
access arbejder ikke med multiple statements så din delete vil ikke fungere - det er primært ' tegnet der er et problem i access og alt du behøver er at skrive fx
pling, altså tegnet ', er meget farligt
i et input-fil.
i alle databaser er der ord man ikke uden videre kan benytte - ordet password er vist et af dem i access, derfor
Insert into userData (username,[password]) values ('hej1','hej2')
fennec & keysersoze > Så hvis jeg har hørt noget om at via et forum, når man postede indlæg til en access database, var det muligt at slette alle data. Dette stoppede først da man lukkede for muligheden for at skrive i forummet. Det er løgn?
fennec > Sidste spørgsmål.. Du har givet mig en sikker metode til lagre. Hvad når jeg skal Selecte? Kan jeg bruge noget i stil med det du har postet, eller skal jeg over i noget helt andet?
Umiddelbart vil jeg anbefale det som keysersoze linker til (eller min egen artikel om parameterisering her på sitet: http://www.eksperten.dk/artikler/1250), da et dynamisk recordset er morderligt resursekrævende (pga. den cursor som benyttes til den slags recordsets).
Jeg er da godt klar over, at et site som kun skal gemme en formular et par gange om dagen ikke går kold pga. den metode, men det er mere princippet i at "spilde" resurser, hvis det ikke er nødvendigt.
Command-objektet egner sig både til at hente og gemme data i en database, så det er oplagt at lære det at kende... :-)
softspot > Jeg har brugt din artikel til at lave min kode.. Dog vil jeg gerne lige have introduceret de metoder osv du bruger. Lad os tage udgangspunkt i din kode:
ADO (og ikke AOD) står for ActiveX Data Objects og er den teknologi som benyttes af de fleste der (stadig) koder i ASP. Det er altså ikke noget nyt i forhold til det du allerede selv har brugt til at åbne din database med (du benytter ADODB.Connection).
Du skal benytte METADATA-elementet for at kunne benytte konstanterne til ADO (f.eks. adVarChar, adParamInput og adCmdText osv.). Det er frem for at benytte del numeriske konstanter for de samme værdier. Du vil andre steder se folk kalde Open-metoden på et recordset med formatet:
rs.Open sql, cn, 3, 3
Men jeg foretrækker nu formatet:
rs.Open sql, cn, adOpenStatic, adLockOptimistic
i stedet for, da de tekstuelle konstanter er væsentlig lettere at forstå en numeriske værdier. Med METADATA-elementet erklæret (eller adovbs.inc inkluderet i siden), kan jeg bruge den sidste metode, ellers skal jeg bruge den første.
METADATA-elementet er ASP's måde at refere til det typelibrary, som COM-komponenten til ADO definerer.
Hvis jeg tager udgangspunkt i denne definition af en parameter:
Så fortæller jeg mit Command-objekt, at jeg vil oprette en parameter som jeg kalder @kodeord. @kodeord skal have type tekst (i mange store databasesystemer hedder denne type bla. VARCHAR, så det er nok derfor den også har fået dette navn i ADO :-)). @kodeord skal desuden kun opfattes som en input-parameter til denne forespørgsel, hvilket betyder at der ikke skal gøres noget for at opsamle noden værdi i denne parameter efter kaldet er udført (man kan også specificere output-parametre som benyttes i forbindelse med stored procedures - dette svarer nogenlunde til VBScript-parametre, til en funktion, der er erklæret med byref foran parameternavnet).
At der står 20, betyder at parameterens MAX må indeholde 20 tegn (hvis den er længere, så bilver der rejst en kørselsfejl og din ASP-kode stoppes (med mindre du har slået "resume next" til "on error", men command-objektet vil givetvis fejl under alle omstændigheder, da der vil mangle en parameter i parameterlisten). Visse parametertyper behøves en specificeret længde (dem der har en naturlig mulighed for variabel længde) og andre har en implicit længde, f.eks. adInteger, der altid er 4 lang. De parametertyper som har en fast (foruddefineret) længde, behøver man ikke specificere længden på, men jeg gør det nu stort set altid, da det ikke koster så meget mere at gøre det og det øger, efter min mening, læsbarheden af koden.
Givetvis fordi ODBC-driveren til MySQL ikke understøtter parametre som MSSQL og Access gør det. Det er du nød til at undersøge driveren for at kunne afgøre... jeg har ingen erfaring med at forbinde til en MySQL, så jeg kan desværre ikke trække på nogen personlige erfaringer i denne forbindelse, men prøv at søge på Google efter:
MySQL ODBC 3.51 Driver Invalid parameter direction
Mange tak til alle der har bidraget.. Muligvis har mange foreslået den samme metode, men da det er præcis hvad softspot har skrevet jeg har brugt får han points. Send svar, og mange tak :)
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.