Parameterisering af databasekald med ASP og ADO

Relaterede dokumenter
Skrevet den 18. Feb 2010 af arne_v I kategorien Programmering / Visual Basic.NET

Database design for begyndere

Database programmerings tips

Parameters. Denne artikel beskriver hvorfor parameters er gode. Den forudsætter lidt kendskab til C# og ADO.NET.

Som sagt kræves der helst lidt viden om OOP hvis man virkelig vil lærer noget, og ikke bare lave copypaste

Ratingsystem i PHP og MySQL

Database tips. Den forudsætter lidt kendskab til SQL men er for mindre erfarne. Denne guide er oprindeligt udgivet på Eksperten.dk

SQL for MySQL-begyndere

Afsending af s vha. ASP

Med register_globals = On får du automatisk adgang til en række variabelnavne i dit script.

PHP 3 UGERS FORLØB PHP, MYSQL & SQL

Introduktion til SQL queries

Listen over reserverede ord er meget lang, men de væsentligste vil jeg beskrive her i denne artikel:

Indholdsfortegnelse Databaser og PHP... 3 Opgave... 4 Opgave... 5 Opgave... 6 Sidste opgave er en lille gæstebog... 7 Kilder og nyttige links:...

Prepared Statements. Denne artikel beskriver hvorfor prepared statements er gode. Den forudsætter lidt kendskab til Java og JDBC.

Dynamisk PHP design OPDATERET

Log ind med PHP. Denne guide er oprindeligt udgivet på Eksperten.dk. Skrevet den 09. May 2011 af dab93 I kategorien Programmering / Andre

I denne artikel vil du ved hjælp af arrays kunne afrunde et decimaltal til et helt tal.

Gæstebog med validering opbygget med MySQL

Loginsystem (med MySQL)

Den forudsætter kendskab til C++ og lidt kendskab til SQL og MySQL C API.

I mit script tager jeg højde for det problem ved, at gemme et unikt tal mellem 0-9 på 6 cifre og derved vil de så blive vist som 2 online.

Filen global.asa, en asp programmørs ven

Tagwall med Php & MySQL

Brugerdefineret menuer i Access

applikation----x----odbc driver manager----foobar ODBC driver----foobar database

Kontrol-strukturer i PHP

Derfor vil jeg bygge dette eksempel på een table hvor der kan tilkyttes personer til ALLE noder og der kan tilføjes et vilkårligt antal niveauer

Delphi og Databaser for begyndere

Uploade billeder eller andre filer ved hjælp af php og mysql

PHP Snippets. De små korte. Skrevet af Daniel Pedersen

Fotoalbum i Access - del 1

En Kort Introduktion til Oracle

Hvorfor skal vi bruge objekt orienteret databaser?

MySQL C API. Denne artikel beskriver hvordan man bruger MySQL C API. Der er beskrivelse af build med forskellige compilere.

Hvad er Objekter - Programmering

De vigtigste SQL-sætninger. SQL kap Oprette database. DDL og DML

At klippe en streng over på det mest hensigtsmæssige sted

Begrynder til at lave log ind system

Arrays i PHP. Denne guide er oprindeligt udgivet på Eksperten.dk. Skrevet den 04. Feb 2009 af taskmgr I kategorien Programmering / PHP

Flerbruger miljø, opdel database

Bemærk! Et PHP script har kun brug for at forbinde én gang til databaseserveren. Det kan så sagtens udføre flere kommandoer vha. denne forbindelse.

Procesbeskrivelse - Webprogrammering

Kom godt i gang med Hostcenter Danmarks Webadmin

Introduktion til funktioner, moduler og scopes i Python

Foto-Applikation Dokumentation. Et Kod-i-Ferien projekt

Reeksamen, DSDS, forår 2008

I denne artikel, vil der blive gennemgået de grundlæggende PHP-funktioner, såsom udskrift til skærmen, tid og dato og if-sætningen.

Databaseadgang fra Java

Arkitektur for begyndere

Dokumentering af umbraco artikeleksport:

I denne artikel vil vi bruge en User klasse som vi så vil gruppere på forskellige måder.

OPC Access 3.0 opdatering via Stored Procedure

Ekstra hastighed med array's i Excel-VBA

Aftenskole i programmering sæson Core Data del 2. Sæson 2-13

MsSQL: Basal performance tuning, part 1

SWC eksamens-spørgsmål. Oversigt

Anvendelse af metoder - Programmering

Øvelse 9. Klasser, objekter og sql-tabeller insert code here

Indholdsfortegnelse Forord...8 Makroer samt aktivere Udvikler-fanen...10 Makrosikkerhed (Sikkerhedsindstillinger)...13

- A) Overskrift Hvis du ikke kan finde på en oplagt overskrift lige nu, så skriv bare et eller andet. Du kan redigere i det senere:

Hack of the Month opgave 2

Undtagelseshåndtering i C#

//Udskriver System.out.println("Hej " + ditfornavn + " " + ditefternavn + "."); System.out.println("Du er " + dinalder + " aar gammel!

Exceptions i Delphi. Try except

Umbraco installationsvejledning

Serversideprogrammering, CMS og eshop. Dag 1: Introduktion og serverside programmering Niels Østergaard

VÆR EFFEKTIV SOM SAS PROGRAMMØR MED SAS ENTERPRISE GUIDE 7.12 GEORG MORSING

Datatransport Import & Eksport af data Generelt Import/eksport Felter i Import og Eksport... 5

Den forudsætter kendskab til XML og VB.NET men ikke til brug af XML i VB.NET.

Upload af billeder/filer for nybegyndere Del. 2

Skriftlig opgave. Designtanker i database-nære systemer

Sådan kan du sende data fra din egen hjemmeside til JitBesked via en HTML-JDF.

Koden i denne guide vil kun virke i Flash MX 2003 og MX ikke ældre versioner!

Vejledning til Teknisk opsætning

ListView i Access del 2

Excel som database i ASP via ADO

Mozilla Firefox (tidligere Firebird): Fremhæve ord

Begrænsninger i SQL. Databaser, efterår Troels Andreasen

Import af rekursivt (parent-child) hierarki i Palo

Send fra Access.

Værktøjer fra værktøjskassen. Søren Breddam, Stevns Kommune

Sådan skriver du artikler til Eksperten!

Vejledning KPK Online Prøverum

Microsoft Log Parser, Windows logfil analyse

- 1) Overskrift Hvis du ikke kan finde på en oplagt overskrift lige nu, så skriv bare et eller andet. Du kan redigere i det senere:

GeoGIS2020. Installation. Udkast. Revision: 1 Udarbejdet af: BrS Dato: Kontrolleret af: Status: Løbende Reference: Godkendt af:

Programmering i C. Lektion september 2009

Denne artikel gennemgår kort nogle mulighederne for brug af XML i ASP. Det sker ved brug af eksempler. Eksemplerne vil være i VBS.

Views etc. Databaser

Udviklingstab, og hvordan man sætter instilling i dansk office 2007 som jeg bruger herhjemme.

Kom godt igang med OpenMeetings

Den forudsætter kendskab til XML og C# men ikke til brug af XML i C#.

Midttrafik TRAFIKADMINISTRATION. Brugermanual august-2013 vers. 1.2

I denne arktikle går jeg gennem Slet, Ret og Opret data i en MySQL database. der er også en lille del i den hvor den postere datanen ud i en løkke

IT projekt person galleri

Send fra Java. Denne artikel fortæller hvad man skal bruge og hvordan man skal kode for at sende fra Java.

Scratch. - introduktionshæfte

Sproget Rascal (v. 2)

Transkript:

Denne guide er oprindeligt udgivet på Eksperten.dk Parameterisering af databasekald med ASP og ADO Jeg har efterhånden set en del spørgsmål her på Eksperten vedr. SQL injections og hvordan man kan beskytte sig. Efter min opfattelse er det rigtige svar: Parameterisering! Dette vil jeg forsøge at beskrive hvordan gøres med Commandobjektet (ADO og ASP). Skrevet den 13. Apr 2010 af softspot I kategorien Programmering / ASP Ændringslog 18-11-2008: Artikel oprettet. 24-11-2008: Tilføjelse af nyt afsnit om genbrug af command-objektet, samt sektion med kommentar til kommentar. 17-06-2009: Ombrydning af kodeeksempler, så de ikke skaber scrollbars i rammerne til kodeeksemplerne. 13-04-2010: Tilføjelse af en kort udgave til kald af Command-objektet, samt eksempel på indpakning af Command-objekt oprettelsen. Den gængse metode En gængs metode at lave databasekald i ASP, er at sammensætte en SQL-streng af nogle SQL kommandoer og nogle parametre. Dette er dog en kilde til problemer på flere områder. Dels risikerer man at typen af en parameter ikke stemmer overens med det felt man forsøger at gemme data i, dels bliver man sårbar overfor "SQL-injections". Ydermere har strengsammensætningsmetoden også en tendens til at blive uoverskuelig, hvis man ikke holder en stram disciplin. Eksempel på strengsammensat SQL: dim sql sql = "SELECT * " & _ "FROM tabel " & _ "WHERE kodeord = '" & request.querystring("kodeord")& "' " & _ "AND brugernavn = '" & request.querystring("brugernavn") & "'" Når du har sådan en konstruktion i din kode, skal alarmklokkerne begynde at ringe, fordi du har åbnet døren på vid gab for SQL-injections. Request.QueryString er som bekendt værdier der sendes via url'en og er derfor noget af det simpleste at overføre til en side. Det bliver ikke meget bedre af at det er Request.Form der benyttes! En begynder kan relativt let POSTe en form til en url. Nu kunne jeg begynde at skrive en masse om hvordan man modellerer sine input, så de er sikret mod SQLinjections, men det vil jeg ikke (det er der skrevet mange andre artikler om på internettet). Nej, jeg vil i stedet slå et slag for parametre og Command-objekter i ADO! Parametre og Command-objektet Med parametre kan du være nogenlunde sikker på, at databasekaldet (hvis det når databasen) er korrekt og fri for injections. Før jeg går igang med at eksemplificere brugen af Command, vil jeg starte med at få en ting på plads, nemlig de konstanter som benyttes i forbindelse med ADO. Konstanterne gør koden lettere og mere

intuitiv at læse. Der er umiddelbart 3 muligheder for at få disse konstanter ind i koden (faktisk 4, men at sidde og definere dem selv, synes jeg er lidt omsonst, så den vil jeg ikke foreslå): 1. Du kan inkludere en fil (adovbs.inc) i den side som benytter ADO og dermed få adgang til konstanterne i den specifikke side. Dette synes jeg dog ikke specielt godt om, da man dels skal sørge for at den include er med hver gang man skal bruge ADO, dels lægger den en ekstra belastning på serveren, i og med den skal indlæses i den samlede side hver gang siden kaldes. Du kan læse lidt mere om denne metode her: http://msdn.microsoft.com/en-us/library/ms676526(vs.85).aspx 2. Et noget bedre alternativ er at erklære et METADATA-element i siden, som peger på TypeLibrary til ADO. På denne måde skal serveren ikke bruge kræfter på at indlæse en ekstra fil hver gang siden vises. Dog har denne metode stadig den svaghed, at man skal huske dette METADATA-element hver gang ADO skal bruges. 3. Den bedste løsning er efter min mening, at erklære førnævnte METADATA-element i applikationens global.asa-fil, da man så har adgang til ADO-konstanterne fra alle sider i applikationens scope. Applikationens scope omfatter altså alle filer og mapper (og undermapper) som ikke definerer en ny virtuel applikation. Virtuelle applikationer har deres eget scope og skal derfor erklære METADATA-elementet i sin egen global.asa for at få adgang til konstanterne. METADATA-elementet ser således ud: <!-- METADATA TYPE="typelib" uuid="00000205-0000-0010-8000-00aa006d2ea4" --> Igang med Command-objektet Nu er vi klar til at kaste os over Command-udgaven af tidligere viste databaseopslag. Det kunne tage sig således ud: dim sql, cmd, rs dim kodeord, brugernavn kodeord = request.querystring("kodeord") brugernavn = request.querystring("brugernavn") sql = "SELECT * " & _ "FROM tabel " & _ "WHERE kodeord =? " & _ "AND brugernavn =?" 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! ' Eller en quick and dirty udgave som kan bruges i mange tilfælde i stedet for ovenstående: dim sql, cmd, rs dim kodeord, brugernavn kodeord = request.querystring("kodeord") brugernavn = request.querystring("brugernavn") sql = "SELECT * " & _ "FROM tabel " & _ "WHERE kodeord =? " & _ "AND brugernavn =?" set rs = cmd.execute(, array(kodeord,brugernavn)) ' '... og resten af databaseoperationerne her! ' Denne metode kan som nævnt bruges i mange tilfælde og er noget mere kompakt og tilgængelig end versionen med eksplicitte parametererklæringer. Der kan dog være tilfælde hvor det er nødvendigt med mere kontrol over parametrenes typer og så må man "tilbage" til den lange udgave. Regler der skal overholdes Der er nogle ting man skal være opmærksom på i forbindelse med parameterisering via Commandobjektet. Jeg vil prøve at komme ind på de vigtigste herunder. Angivelse af parameterværdier (pladsholdere) Der hvor man ønsker at indsætte en parameter i SQL-sætningen, placeres et spørgsmålstegn. Der skal ikke tages hensyn til typen af parameteren i SQL-sætningens syntaks, dvs. der skal ikke apostroffer (') omkring tekst-parametre eller hash (#) omkring datoer (i Access), da dette styres under oprettelsen af parameteren i command-objektets parameter-collection. Sekvens af parametre Det er vigtigt, at parametrene oprettes i command-objektetks parameter-collection, i den rækkefølge de forekommer i SQL-sætningen, da ADO ikke har nogen anden måde at koble parametre til SQL-sætningen end sekvensen (i og med pladsholdere for parametre udgøres af et spørgsmålstegn har de ikke nogen værdi i forhold til at identificere feltet).

Navngivning af parametre Det er ikke så vigtigt hvad man kalder sine parametre, blot man sørger for at sende dem i den rækkefølge de er angivet i SQL-sætningen. For læsbarhedens og gennemskuelighedens skyld vil jeg da anbefale, at man benytter feltets navn til parameteren, så der er mindre tvivl om koblingen af en parameter til SQLsætningen. Typen af parametre Det er vigtigt, at typen på parameteren stemmer overens eller er kompatibel med den type feltet har i databasen, da ADO ellers vil kvittere med en fejl. Ligeledes er det vigtigt, at typen på værdien af parameteren er kompatibel med den type, som parameteren er erlæret med. Hvis ikke den er det, vil ADO ligeledes kvittere med en fejl. Typiske fejl er integer-parametre som fødes med tomme strenge og dermed ikke er gyldige numeriske værdier, men også tomme dato'er eller strenge der er for lange til at passe ned i den definerede parameter giver problemer. Man slipper altså ikke for at validere brugerens data, selvom man benytter Command-objektet! Understøttelse af parametre Undestøttelsesgraden af parameterisering er forskellig fra "provider" til "provider" og man skal derfor undersøge, om den databasedriver man benytter, understøtter de features man benytter. Der findes muligheder for at spørge ADO om disse ting, men det er ikke noget jeg har benyttet mig af, da jeg altid har arbejdet i et homogent miljø og dermed altid har vidst hvad den driver jeg benytter kan og ikke kan. Derfor vil jeg henvise dig til MSDN eller Google for at finde mere avancerede features i forbindelse med ADO og Command-objektet. Med disse ting på plads kan jeg prøve at demonstrere et par andre typiske databaseoperationer hvor Command-objektet er handy. Oprettelse af nye data Oprettelse af data i en tabel er et typisk scenarie, hvor brugeren er leverandør af data og et andet typisk eksempel på, hvor man skal være ekstra opmærksom på injectionforsøg. En insert kunne håndteres således ved brug af command: dim sql, cmd, recordcount dim kodeord, brugernavn, email kodeord = request.form("kodeord") brugernavn = request.form("brugernavn") email = request.form("email") sql = "INSERT INTO tabel (kodeord, brugernavn, email) VALUES(?,?,?)" cmd.parameters.append cmd.createparameter("@kodeord", _ advarchar, adparaminput, 20, kodeord) cmd.parameters.append cmd.createparameter("@brugernavn", _ advarchar, adparaminput, 20, brugernavn) 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." response.write " Forsøg evt. igen eller kontakt support." end if Som det ses, er der ikke meget forskel på hvordan Command-objektet benyttes mht. initiering og opsætning af parametre. Selve kaldet returnerer, i dette tilfælde, ikke noget brugbart recordset, så derfor undlader jeg at gemme det i en variabel. I stedet sender jeg en parameter med til cmd.execute for at få oplysninger om, hvormange rækker det blev påvirket af min INSERT. Dette benytter jeg til at sandsynliggøre, at indsættelsen gik godt. I dette tilfælde skal recordscount gerne indholde 1, da der oprettes netop én ny række i tabellen. Samme mønster vil gøre sig gældende for UPDATE og DELETE. Stored Procedues Hidtil har jeg kun behandlet tekstbaserede commands, men hvis jeg har en stored procedure, som skal udføres, er opskriften nogenlunde den samme, blot med den ændring, at cmd.commandtype skal sættes til adcmdstoredproc i stedet for adcmdtext. Eksempel, hvor jeg har en stored procedure som sletter en bruger fra databasen og til dette formål tager den brugerens navn som parameter: sql = "spsletbruger" cmd.commandtype = adcmdstoredproc cmd.parameters.append cmd.createparameter("@brugernavn", _ advarchar, adparaminput, 20, brugernavn) recordcount = 0 cmd.execute recordcount if recordcount = 1 then response.write "Dine oplysninger er nu slettet." else response.write "Dine oplysninger blev IKKE slettet." response.write " Forsøg evt. igen eller kontakt support." end if Som med INSERT-eksemplet er der heller ikke umiddelbart noget brugbart resultat efter denne operation, så jeg vælger bare at aflæse antallet af rækker som blev påvirket af denne handling.

Genbrug af command-objektet Skulle man have behov for at udføre den samme databaseoperation flere gange efter hinanden, kan man med fordel benytte det samme command-objekt og blot udskifte parametrenes værdier (det er vel en af de andre vigtige årsager til at benytte command-objektet, da man på denne måde kan vinde noget performance i og med man slipper for at oprette og nedlægge command-objekter for hver iteration). Det kunne tage sig nogenlunde således ud: dim sql, cmd, recordcount dim arrbrugere, bruger arrbrugere = array( _ array("bruger1","kode1","mail1@example.dk"), _ array("bruger2","kode2","mail2@example.dk"), _ array("bruger3","kode3","mail3@example.dk"), _ array("bruger4","kode4","mail4@example.dk"), _ array("bruger5","kode5","mail5@example.dk") _ ) sql = "INSERT INTO tabel (kodeord, brugernavn, email) VALUES(?,?,?)" cmd.parameters.append cmd.createparameter("@kodeord", _ advarchar, adparaminput, 20) cmd.parameters.append cmd.createparameter("@brugernavn", _ advarchar, adparaminput, 20) cmd.parameters.append cmd.createparameter("@email", _ advarchar, adparaminput, 255) for each bruger in arrbrugere cmd.parameters("@kodeord").value = bruger(1) cmd.parameters("@brugernavn").value = bruger(0) cmd.parameters("@email").value = bruger(2) recordcount = 0 cmd.execute recordcount if recordcount = 0 then response.write "Oplysninger om " & bruger(0) response.write " kunne IKKE gemmes!" end if next Lidt dovenskab skader vel ikke Som mange nok har luret, er selve oprettelsen af command-objektet en relativ triviel opgave og der kan spares en del liniers kode (set på applikationsplan), hvis man lige pakker den del lidt ind. Dette har jeg lavet et lille eksempel på herunder.

function CreateTextCommand(conn, sql) dim cmd set CreateTextCommand = cmd end function Funktionen opretter, ikke overraskende, et command-objekt og returnerer dette til den kaldende part. Den kaldende part sparer altså tre liniers triviel kode hver gang, hvilket dels gør tingene hurtigere at kode, men også nemmere at overskue (når først man har lært hvad funktionen CreateTextCommand gør ;-)). Funktionen kan bruges således i praksis (her anvendes quick and dirty-metoden også for at demonstrere hvordan dette kan se ud i en opdateringssituation): dim sql, cmd, recordcount dim kodeord, brugernavn, email kodeord = request.form("kodeord") brugernavn = request.form("brugernavn") email = request.form("email") sql = "INSERT INTO tabel (kodeord, brugernavn, email) VALUES(?,?,?)" set cmd = CreateTextCommand(conn, sql) recordcount = 0 cmd.execute recordcount, array(kodeord, brugernavn, email) if recordcount = 1 then response.write "Dine oplysninger er nu gemt." else response.write "Dine oplysninger blev IKKE gemt." response.write " Forsøg evt. igen eller kontakt support." end if Konklusion Nu er command-objektets mest basale muligheder introduceret og der er rig mulighed for at udbygge sin viden om de features som stilles til rådighed af ADO. Du kan også se, at der ikke umiddelbart er mulighed for at SQL-injicere når der benyttes parametre sammen med Command-objektet, da mulighederne for at snyde med formatet af input, så de påvirker den genererede SQL-sætning, er fjernet. Kravet om at validere input består (som det også gør med strengsammensætningsmetoden), da det stadig kan opstå fejl, hvis data har forkert format i forhold til parametertypen. Fejlhåndtering kan være med til at afbøde dette lidt, men det er som udgangspunkt bedre, at sikre datavaliditet frem for at fejlhåndtere sig

ud af datainvaliditet. Min egen primære kilde til at undersøge mulighederne ved ADO er MSDN, så derfor vil jeg referere til følgende: http://msdn.microsoft.com/en-us/library/ms675532(vs.85).aspx som er programmørens guide og referencemanualen til ADO. http://msdn.microsoft.com/en-us/library/ms676571(vs.85).aspx som er en lille samling af sider der beskriver hvordan man benytter Command-objektet. Der er ingen tvivl om at der findes meget mere om emnet rundt omkring, men mine egne behov er typisk af opslagskarakter, så derfor er det ovenstående materialer jeg benytter mest. Kommentar til kommentar til artiklen arne_v >> Naturligvis! En rigtig vigtig pointe hvis man arbejder med batchoperationer. Jeg har tilføjet et afsnit om dette ("Genbrug af command-objektet"). thesurfer >> Jeg er enig i at man skal beskytte sine kodefiler og vil i princinppet også vælge at beskytte mine filer. Dog er den refererede inc-fil public domain, så den er der nok ikke så stor risiko ved at lade folk hente (hvis bare man lader være med at tilføje sin egen kode i den :-)). erikjacobsen >> Enig. Jeg har desværre kun kendskab til.net ud over ASP, men vil da gerne bekræfte at det også her kan lade sig gøre. Det kan være der herfra kommer en artikel om det på et tidspunkt (hvis der ikke er nogen som kommer mig i forkøbet... UPS! Jeg kan se der allerede er lavet et par stykker af arne_v :-)). Kommentar af erikjacobsen d. 20. Nov 2008 1 Og man kan tilføje, at i alle andre frameworks og lignende, findes en tilsvarende mulighed. Kommentar af thesurfer d. 20. Nov 2008 2 Meget god artikel. Men man må aldrig bruge ".inc"-filer (f.eks. adovbs.inc), da disse filer er ren tekst som ikke bliver afviklet. Dvs, hvis man kan gætte filnavnet (f.eks. hvis man kan genkende systemet/forum/osv), kan man få fat på indholdet af ".inc"-filen (database-oplysninger, brugernavn, kodeord osv).. Brug heller sprogets eget filtype (f.eks. adovbs.asp) og definer variablerne der. Kommentar af arne_v d. 24. Nov 2008 3 Glimrende. Man kan også assigne værdier til parametrene efter at man har created og appended dem. Kommentar af trer d. 07. Dec 2008 4 Fin artikel. Kommentar af windcape d. 22. Nov 2008 5 Kommentar af erizias (nedlagt brugerprofil) d. 07. Jul 2011 6 Kanon artikel, dog savner jeg lidt "hvad gør denne, og hvad gør denne" :) F.eks. hvordan følgende 2 statements kan være lig hinanden:

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 set rs = cmd.execute(, array(kodeord,brugernavn)) For mig at se, får den nederste metode jo ikke at vide om det er varchar, ints eller lignende samt hvor mange tegn det indeholder, som den øverste metode gør :) Det savner jeg lidt i artiklen, men ellers en kanon artikel som fortæller om grundprincipperne af parameteriseringen :)