Avatar billede lakana Nybegynder
12. juli 2008 - 12:40 Der er 12 kommentarer og
1 løsning

Opstår problemer med quotes

Jeg har en formular hvor jeg sender informationer til en database, men når jeg sender "'", så retter den ikke indholdet i databasen. Hvordan kan det dog være?
Avatar billede lakana Nybegynder
12. juli 2008 - 12:44 #1
Når jeg retter det 'manuelt' i min database, så er der ingen problemer.

På selve min side får jeg følgende fejl:
"You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'hehe' WHERE `id` = 15 LIMIT 1' at line 1"
Avatar billede lakana Nybegynder
12. juli 2008 - 12:47 #2
Nå, jeg er bare ikke vant til at arbejde på en server, hvor mysql_real_escape_string() ikke er slået til automatisk :)

Kan man ikke rette det med ini_set, så jeg ikke skal escape hver eneste _POST?
Avatar billede coderdk Praktikant
12. juli 2008 - 13:04 #3
Avatar billede pidgeot Nybegynder
12. juli 2008 - 13:47 #4
Det er ikke mysql_real_escape_string der er slået til automatisk, men magic_quotes_gpc - og det kan ikke gøres i scriptet.

Du skal ind og rette i php.ini hvis det skal være - men det er ikke en holdbar løsning i længden, da magic_quotes forsvinder i PHP6. Den rigtige løsning er at bruge mysqli-funktionerne sammen med parameteriserede SQL-sætninger, eller hvis det ikke kan lade sig gøre, kode som om magic_quotes ikke er slået til (og dermed fjerne dem hvis de er der), og selv kalde mysql_real_escape_string (bemærk dog at escaping aldrig vil være andet end en nødløsning, og parameterisering derfor kun bør fravælges hvis det på ingen måde er muligt at bruge). Det giver den mest portable kode (til hvis du skal skifte server), og er samtidigt den sikkerhedsmæssigt bedste måde at gøre tingene på.
Avatar billede coderdk Praktikant
12. juli 2008 - 14:25 #5
magic_quotes_gpc kan du godt sætte i en .htaccess så vidt jeg husker, prøv at oprette en .htacces med indholdet:

php_flag magic_quotes_gpc on
Avatar billede lakana Nybegynder
12. juli 2008 - 15:01 #6
pidgeot - vil du forklare hvad parametrisering og prepare er? (jeg bruger mysqli)
Avatar billede lakana Nybegynder
12. juli 2008 - 15:09 #7
Hvis jeg har forstået det rigtigt, så bruger man prepare til at 'forberede' en forespørgsel på noget indhold (ligesom sprintf()), og så bruger man parametrisering til at skifte disse "forberedelser" ud med det rigtige indhold, og så samtidig skal jeg fortælle om det er en string, integer eller lignende. Ikke?
Avatar billede lakana Nybegynder
12. juli 2008 - 15:11 #8
Men hvis jeg har forstået det korrekt, så er det jo lige så effektivt at bruge settype() og sprintf(), og så kan jeg ikke se, at det løser mit problem. Men jeg har nok heller ikke helt forstået det :-D
Avatar billede pidgeot Nybegynder
12. juli 2008 - 16:54 #9
Det er korrekt at princippet i en vis grad er ligesom sprintf, men det er også det der gør det sikkert.

De escaping-funktioner som databaserne har er nemlig ikke altid fejlfrie - MySQL og PostgreSQL har begge haft problemer der, og de kan sagtens have nogle endnu, for der er mange aspekter i det - men parameterisering er det betydeligt sværere at lave forketr.

Grunden er at værdier og struktur behandles hver for sig - så alle værdier den får ind vil aldrig kunne opfattes som SQL.

Forestil dig at du har en SQL-sætning der ser sådan ud:

UPDATE tabel SET tekst='hej' WHERE id=15

Hvis 15 kommer direkte fra $_POST, så kunne jeg faktisk have ændret det inden jeg sendte det, så du ender med der står:

UPDATE tabel SET tekst='hej' WHERE id=15 OR 1

...så alle rækker ville blive opdateret med den tekst, fordi 1 vil blive evalueret til sand for alle rækker.

Hvis du havde smidt ' om tallet (det tillader MySQL, selvom man egentlig ikke må), så havde lige det ikke gået, fordi det så havde set sådan ud:

UPDATE tabel SET tekst='hej' WHERE id='15 OR 1'

Men der kunne jeg jo så i stedet skrive ' OR '1, hvilket giver:

UPDATE tabel SET tekst='hej' WHERE id='15' OR '1'

Det er sådan grundlaget for SQL injection, hvilket er grunden til at vi overhovedet har behov for at lave alle de krumspring. Escaping ville gøre at den i stedet blev til:

UPDATE tabel SET tekst='hej' WHERE id='15\' OR \'1'

Og det virker jo umiddelbart fint nok. Problemet er at hvis der er en fejl i den escaping-funktion, så kan jeg måske udnytte den fejl, så min SQL injection alligevel fungerer, og det er jo et problem.

Her kommer parameterisering for alvor til sin ret. Der ville du i stedet give denne SQL:

UPDATE tabel SET tekst=? WHERE id=?

Det gør at MySQL nu ved at den skal have 2 værdier: en der skal bruges som tekst, og en der skal bruges som ID. Uanset hvad jeg måtte finde på at sende til den, så vil jeg ikke kunne slippe SQL igennem, for MySQL ved allerede at det er en værdi den får, og derfor prøver den ikke at fortolke det på nogen måde - selvom værdien til id er "15 OR 1", så ved den at den skal opfatte det som en direkte værdi.

Dermed bliver dit system skudsikkert (mod den slags problemer, vel at mærke), og du kan være fløjtende ligeglad med om der er apostroffer eller andre specielle tegn i inputtet - for MySQL vil ikke fejltolke det.
Avatar billede lakana Nybegynder
12. juli 2008 - 17:31 #10
pidgeot: tak for forklaringen :)

men jeg vil vel stadig være nødsaget til at escape mine strings, og jeg ville vel stadig i $_POST['text'] skrive "d';", og så bliver det til to forskellige forespørgelser - eller hvad? Lige nu bruger jeg sprintf til det:
$sql = sprintf("UPDATE table_name SET text = '%s' WHERE id = %d LIMIT 1", $text, $id);

Det gør vel akkurat det samme. Ikke?

Hvilke mysqli-funktioner er det jeg skal bruge for at gøre som du forslår?
Avatar billede pidgeot Nybegynder
12. juli 2008 - 18:02 #11
Nej, du er ikke nødt til at escape - den eneste grund til man er nødt til det er for at MySQL kan skelne mellem værdier og syntaks i en normal SQL-sætning.

Med en parameteriseret sætning ved den det inden værdierne kommer ind - og derfor ved den også at alt der er en værdi, skal betragtes som sådan, så du skal hverken have ' om strenge eller bekymre dig om hvorvidt sådan en er i det data du sender ind (eller for den sags skyld andre tegn der kan påvirke selve SQL'en) - det holder den styr på, fordi den med parameterisering ved hvornår noget er værdi og hvornår noget er SQL. Derfor er det ligegyldigt om $_POST['text'] indeholder "hej med dig" eller "d';" - den ved med parameterisering at det er en *værdi*, som derfor ikke kan indflyde på hvordan SQL-sætningen fortolkes.

Den primære forskel på at bruge sprintf og parameterisering er at sprintf bliver behandlet inden MySQL kender til forespørgslen - og dermed ved MySQL ikke på forhånd hvor der er tale om SQL og hvornår der er tale om værdier, hvorfor du er lige vidt.

Kig på mysqli_stmt_prepare (http://dk2.php.net/manual/en/mysqli-stmt.prepare.php) samt de relaterede funktioner - det er dem du skal have fat i.
Avatar billede lakana Nybegynder
12. juli 2008 - 18:19 #12
lækkert :-D smid et svar!
Avatar billede pidgeot Nybegynder
12. juli 2008 - 18:55 #13
Værsgo :)
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
Vi tilbyder markedets bedste kurser inden for webudvikling

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