Avatar billede Slettet bruger
14. august 2010 - 11:58 Der er 13 kommentarer og
1 løsning

SQL injection - er dette sikkert ?

Jeg er ved at opbygge en SELECT med input fra brugeren (den bandit).

PHP:
$SQL = "SELECT hemmelighed FROM tabel WHERE kode='" .
    str_replace('\'','',$_POST['kode']) .
"'";
Altså - Jeg fjerner evt. enkelt-plinger - intet andet!
Avatar billede arne_v Ekspert
14. august 2010 - 14:20 #1
Nej - den er ikke sikker.

Beskyttelse:

                              verdens      tekst med    virker
                              dummeste    specielle    også med
                              hacker      charset      tal
str_replace                      ja            nej      nej
addslashes                      ja            nej      nej
mysql_escape_String              ja            nej      nej
mysql_real_escape_String        ja            ja        nej
mysqli og prepared statement    ja            ja        ja
Avatar billede Slettet bruger
14. august 2010 - 15:13 #2
Hvad mener du med sidste kolonne: "virker også med tal"
Hvordan man værdien i $_POST['kode'] bryde ud af mine omklamrende ' og '
- når jeg har frataget den muligheden for at indeholde ' selv ?
(og tegnsættet i PHP-filen er UTF-8)
Avatar billede arne_v Ekspert
14. august 2010 - 15:46 #3
$sql = '... WHERE id=' . $_POST['id']

ingen dapper omkring tal => alt der bygger på dapper duer ikke.
Avatar billede Slettet bruger
14. august 2010 - 23:52 #4
Prøvede lige at poste det på StackOverflow også : )
(http://stackoverflow.com/questions/3484896/sql-injection-is-this-oneliner-safe)

De fleste er enige om at prepared statements ER den sikreste metode.

Men det bliver for kompliceret, jeg bygger min søge-query dynamisk, på basis af en masse mulige til/fra-valg (bla. nogle "fancy parenteser" omkring fra/til-datoer), og mit lille hovede kan ikke rumme det, hvis ikke jeg kan se den endelige query i én lang streng.

SÅ, jeg fremturer, og hærder mine streng parametre således:
... WHERE kode='".mysql_real_escape_String($_POST['felt'])."'"

og tal-parametre således
... WHERE iD='".((int) $_POST['felt'])."'"


Men det er på trods - point'ene er dine for det "mest korrekte" svar.
Avatar billede arne_v Ekspert
15. august 2010 - 00:00 #5
svar
Avatar billede arne_v Ekspert
15. august 2010 - 00:03 #6
Jeg vil lige bemærke at http://ilia.ws/archives/103-mysql_real_escape_string-versus-Prepared-Statements.html ikke er komplet.

mysql_real_escape_string tillader nemlig at man sender en connection med så den kender charset!
Avatar billede arne_v Ekspert
15. august 2010 - 00:05 #7
I professionel software udvikling er der formentlig meget få tilbage som ikke bruger prepared statement (PHP, Java) / parameters (MS).
Avatar billede arne_v Ekspert
15. august 2010 - 00:07 #8
Du kan sagtens bruge prepared statement og opbygge din SQL dynamisk.

Du opbygger den bare med ? fremfor værdier og så angiver du værdierne separat.
Avatar billede Slettet bruger
15. august 2010 - 08:08 #9
Opbygningen af SQL'en fylder lidt over 100 linjer og jeg ender (worst case) med et 14 ledet monster!

Hvordan holder jeg styr på så lang en parameter-liste ?
- et array måske..: $param[++$pAntal] = $post['felt'].. men hvad så ?
Avatar billede groyk Novice
15. august 2010 - 21:17 #10
.. WHERE iD='".((int) $_POST['felt'])."'" Virker ikke med decimaltal.

mvh Simon
Avatar billede Slettet bruger
16. august 2010 - 10:30 #11
#10>
Det skal det heller ikke : )
- det er til "id'er" (strenge) som jeg ved består af ene tal (hvis de er valide).
Avatar billede arne_v Ekspert
21. august 2010 - 17:40 #12
Man kan godt opbygge komplekse SQL saetninger samtidigt med at man bruger  prepared statement.

Demo med mysqli:


<?php
    //$xf1 = 3;
    $xf2 = 'BB';
    $con = new mysqli('localhost', 'root', '', 'Test');
    if(mysqli_connect_errno()) die(mysqli_connect_error());
    $first = true;
    $sql = 'SELECT f1,f2 FROM t1';
    $typ ='';
    if(isset($xf1)) {
        $sql .= $first ? ' WHERE' : ' AND';
        $sql .= ' f1 = ?';
        $typ .= 'i';
        $val[] = &$xf1;
        $first = false;
    }
    if(isset($xf2)) {
        $sql .= $first ? ' WHERE' : ' AND';
        $sql .= ' f2 = ?';
        $typ .= 's';
        $val[] = &$xf2;
        $first = false;
    }
    if($stmt = $con->prepare($sql)) {
        call_user_func_array(array($stmt, 'bind_param'), array_merge(array($typ), $val));
        $stmt->execute();
        $stmt->store_result();
        $stmt->bind_result($f1, $f2);
        while ($stmt->fetch()) {
            print $f1 . ' ' . $f2 . "\n";
        }
        $stmt->close();
    } else {
        die($con->error);
    }
    $con->close();
?>


Demo med PDO (lidt mere elegant!):


<?php
    //$xf1 = 3;
    $xf2 = 'BB';
    $db = new PDO('mysql:host=localhost;dbname=Test');
    $first = true;
    $sql = 'SELECT f1,f2 FROM t1';
    if(isset($xf1)) {
        $sql .= $first ? ' WHERE' : ' AND';
        $sql .= ' f1 = :f1';
        $val[':f1'] = $xf1;
        $first = false;
    }
    if(isset($xf2)) {
        $sql .= $first ? ' WHERE' : ' AND';
        $sql .= ' f2 = :f2';
        $val[':f2'] = $xf2;
        $first = false;
    }
    if($stmt = $db->prepare($sql)) {
        $stmt->execute($val);
        while ($row = $stmt->fetch()) {
            print $row['f1'] . ' ' . $row['f2'] . "\n";
        }
        $stmt->closeCursor();
    } else {
        die($con->errorInfo());
    }
?>
Avatar billede Slettet bruger
23. august 2010 - 20:34 #13
"call_user_func_array" - Snedigt. Dén kendte jeg ikke, tak : )

PDO - Ja, kan godt se at det er dén vej jeg skal.
- Har man mulighed for at se det samlede SQL, inden execute ?
Avatar billede arne_v Ekspert
23. august 2010 - 20:50 #14
Det tror jeg ikke.

Ved nogle implementation sker merge af SQL og vaerdier i databasen ikke i app.
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
Computerworld tilbyder specialiserede kurser i database-management

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