Avatar billede s0mmer Nybegynder
18. november 2008 - 12:43 Der 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å?

200 points til mest forklarende og bedste svar :)
Avatar billede keysersoze Guru
18. november 2008 - 13:36 #1
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
Avatar billede fennec Nybegynder
18. november 2008 - 13:41 #2
En sikker metode til indsættelse:

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 :)
Avatar billede s0mmer Nybegynder
18. november 2008 - 13:47 #3
keysersoze > Så du mener simpelthen som på sitet, at jeg skal sikre mig mod SQL injections og droppe tanken om det er det at åbne og lukke databasen?

fennec > Hvis man forestiller dine inputs stammer fra en form, ville det så ikke stadig være muligt med SQL injections?
Avatar billede fennec Nybegynder
18. november 2008 - 13:58 #4
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 (').

Set Rs = Server.CreateObject("ADODB.Recordset")
Rs.Open "TabelNavn", Conn, 2, 2
Rs.AddNew
Rs("EnInt") = request.form("tal")
Rs("enDato") = request.form("date")
Rs("EnFloat") = request.form("float")
Rs("EnTekst") = request.form("tekst")
Rs.Update
Rs.close
Avatar billede fennec Nybegynder
18. november 2008 - 14:00 #5
Man kan dog som ekstra sikkerhede typecaste sine værdier inden man bruger dem, men det er normalt ikke nødvendigt:

Rs("EnInt") = cInt(request.form("tal"))
Rs("enDato") = cDate(request.form("date"))
Rs("EnFloat") = cDbl(request.form("float"))
Rs("EnTekst") = cStr(request.form("tekst"))
Avatar billede fennec Nybegynder
18. november 2008 - 14:02 #6
... Parameters statements (som keysersoze link snakker om) er også automatisk sikret.
Avatar billede keysersoze Guru
18. november 2008 - 14:07 #7
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.
Avatar billede s0mmer Nybegynder
18. november 2008 - 14:12 #8
fennec > Hvad betyder din Rs.Open.. hvor kommer Conn fra ? og hvad 2,2 ?

keyserzone > Så du mener hvis jeg går med fennec's metode så er jeg dækket ind? Og hvad mener du med uden for webscope?

Beklager de mange spørgsmål. Det er vigtigt for mig at have forstået det helt rigtigt.
Avatar billede fennec Nybegynder
18. november 2008 - 14:25 #9
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.
Avatar billede s0mmer Nybegynder
18. november 2008 - 14:30 #10
fennec > Begyndte igår :) Men er ret inde i PHP og jeg begynder at se en masse ligheder såsnart syntaxen falder på plads..

Selvom databasen ikke ligger i samme mappe, burde den vel stadig kunne hentes af andre brugere der har stien, hvis hjemmesiden gør brug af den?
Avatar billede fennec Nybegynder
18. november 2008 - 14:39 #11
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.
Avatar billede s0mmer Nybegynder
18. november 2008 - 14:43 #12
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?
Avatar billede fennec Nybegynder
18. november 2008 - 14:56 #13
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.

SQL injection problematikken er beskrevet på wiki:
http://en.wikipedia.org/wiki/SQL_injection
Avatar billede keysersoze Guru
18. november 2008 - 14:58 #14
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')
Avatar billede keysersoze Guru
18. november 2008 - 14:59 #15
"i et input-fil." = i et input-felt
Avatar billede s0mmer Nybegynder
18. november 2008 - 15:05 #16
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?
Avatar billede fennec Nybegynder
18. november 2008 - 15:08 #17
Ja. Med access er det ikke muligt.
Avatar billede s0mmer Nybegynder
18. november 2008 - 15:11 #18
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?
Avatar billede fennec Nybegynder
18. november 2008 - 15:15 #19
Du kan godt bruge noget ala det jeg har vist, men det er ikke tilrådig. Der skal du hellere over i det keysersoze linkede til i første post.
Avatar billede softspot Forsker
19. november 2008 - 14:24 #20
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... :-)
Avatar billede s0mmer Nybegynder
27. november 2008 - 11:32 #21
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:

dim sql, cmd, rs
dim kodeord, brugernavn

kodeord = request.querystring("kodeord")
brugernavn = request.querystring("brugernavn")

sql = "SELECT * FROM tabel WHERE kodeord = ? and brugernavn = ?"
set cmd = Server.CreateObject("ADODB.Command")
set cmd.ActiveConnection = conn
cmd.CommandText = sql
cmd.CommandType = adCmdText
cmd.Parameters.Append cmd.CreateParameter("@kodeord", adVarChar, adParamInput, 20, kodeord)
cmd.Parameters.Append cmd.CreateParameter("@brugernavn", adVarChar, adParamInput, 20, brugernavn)
set rs = cmd.Execute()
'
' ... og resten af databaseoperationerne her!
'

For det første.. Hvad er AOD?
Den metatag du henviser til man skal bruge for at det kan fungere, hvorfor? og hvor kommer den fra?

Derudover, ka du kort introducere hvad, adVarChar, adParamInput, 20 betyder?

Og så tror jeg det er done ;)
Avatar billede softspot Forsker
27. november 2008 - 12:24 #22
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:

cmd.Parameters.Append cmd.CreateParameter("@kodeord", adVarChar, adParamInput, 20, kodeord)

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.
Avatar billede s0mmer Nybegynder
28. november 2008 - 02:07 #23
softspot > takker rigtig mange gange for uddybelsen.

måske kan du se hvad jeg gør galt:

øverst i koden har jeg meta-tagget:
<!-- METADATA TYPE="typelib" uuid="00000205-0000-0010-8000-00AA006D2EA4"  -->

kode:
Dim sConnection, objConn , objRS

          sConnection = "DRIVER={MySQL ODBC 3.51 Driver}; SERVER=localhost; DATABASE=xxx; UID=xxx;PASSWORD=xxx; OPTION=3"

          Set objConn = Server.CreateObject("ADODB.Connection")

          objConn.Open(sConnection)

         
          dim sql, cmd, recordCount
          dim kodeord, brugernavn, email
          kodeord = request.form("txtCompany")
          brugernavn = request.form("txtName")
          email = request.form("txtEmail")
          sql = "INSERT INTO test (brugernavn, kodeord, email) VALUES(?,?,?)"
          set cmd = Server.CreateObject("ADODB.Command")
          set cmd.ActiveConnection = objConn
          cmd.CommandText = sql
          cmd.CommandType = adCmdText
          cmd.Parameters.Append cmd.CreateParameter("@brugernavn", adVarChar, adParamInput, 20, brugernavn)
          cmd.Parameters.Append cmd.CreateParameter("@kodeord", adVarChar, adParamInput, 20, kodeord)
          cmd.Parameters.Append cmd.CreateParameter("@email", adVarChar, adParamInput, 255, email)
          recordCount = 0
          cmd.Execute recordCount
          if recordCount = 1 then
              response.write "Dine oplysninger er nu gemt."
          else
              response.write "Dine oplysninger blev IKKE gemt. Forsøg evt. igen eller kontakt support."
          end if


får flg fejl:
Error Type:
ADODB.Parameter.1 (0x80020009)
Invalid parameter direction.
/ASP/dbcon.asp, line 51
Avatar billede softspot Forsker
28. november 2008 - 08:34 #24
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
Avatar billede s0mmer Nybegynder
28. november 2008 - 10:30 #25
softspot > Kan jeg få et eksempel hvor man connecter til en MSSQL database istedet?
Avatar billede softspot Forsker
28. november 2008 - 12:18 #26
Med en OLE DB provider til en MS SQL Server 2000 kunne det se således ud:

  sConnection = "Provider=SQLOLEDB.1;Password=kodeord;Persist Security Info=True;User ID=brugernavn;Initial Catalog=databasenavn;Data Source=databaseservernavn"

  Set objConn = Server.CreateObject("ADODB.Connection")

  objConn.Open sConnection
Avatar billede s0mmer Nybegynder
01. december 2008 - 12:15 #27
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 :)
Avatar billede softspot Forsker
01. december 2008 - 12:24 #28
Velbekomme :)

NB: Jeg her ikke noget problem med at dele med de øvrige indlægsydere (deres deltagelse har været mindst lige så kvalificeret som min :))
Avatar billede fennec Nybegynder
01. december 2008 - 13:24 #29
nej tak
.o) <-- One Eyed Jack
Avatar billede softspot Forsker
08. december 2008 - 22:55 #30
Tak for point :)
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