Fixing a sql injection

Σε αυτή την περιοχή μπορείτε να βρείτε ή να αναζητήσετε πληροφορίες σχετικές με την PHP

Συντονιστές: WebDev Moderators, Super-Moderators, PHP Moderators

Απάντηση
netpumber
Δημοσιεύσεις: 103
Εγγραφή: 08 Μαρ 2009 19:06

Fixing a sql injection

Δημοσίευση από netpumber » 08 Μαρ 2009 19:13

Γεια σας έχω αυτον το vulnerable κωδικα php:

Κώδικας: Επιλογή όλων

if (!$_GET['id']) $title = $table;
                        else
                        {
                            $result = query('SELECT name FROM products WHERE id='.$_GET['id'].'');
                            $row = mysql_fetch_array($result, MYSQL_NUM);
                            $title = $row[0];
                        }
Μπορείτε να μου προτείνετε τον καλύτερο κατα την άποψή σας τρόπο για να φιξάρω το κενό ?

αυτό που σκέφτηκα εγώ είναι :

Κώδικας: Επιλογή όλων

function quote_smart($value)
{
    if( is_array($value) ) {
        return array_map("quote_smart", $value);
    } else {
        if( get_magic_quotes_gpc() ) {
            $value = stripslashes($value);
        }
        if( $value == '' ) {
            $value = 'NULL';
        } if( !is_numeric($value) || $value[0] == '0' ) {
            $value = "'".mysql_real_escape_string($value)."'";
        }
        return $value;
    }
}
Ευχαριστώ πολύ...

Άβαταρ μέλους
dva_dev
Script Master
Δημοσιεύσεις: 3790
Εγγραφή: 16 Σεπ 2005 01:32
Επικοινωνία:

Fixing a sql injection

Δημοσίευση από dva_dev » 08 Μαρ 2009 22:40

Βλέπω τον κόσμο που χρησιμοποιεί php-mysql να έχει μείνει κολλημένος σε συγκεκριμένες τεχνικές (μάλλον παλαιολιθικές).
Μήπως είναι προτιμότερο να προχωρήσεις σε prepared statements και παραμέτρους;
Π.χ. (χωρίς να χρησιμοποιείται το mysqli)

Κώδικας: Επιλογή όλων

<?php
    mysql_query&#40;'PREPARE test_query FROM "SELECT name FROM PRODUCTS WHERE id=?";',$conn&#41;;

    mysql_query&#40;'SET @test_param='.mysql_escape_string&#40;$_GET&#91;'id'&#93;&#41;,$conn&#41;;
    $result = mysql_query&#40;'EXECUTE test_query USING @test_param;',$conn&#41;;
    $row = mysql_fetch_array&#40;$result, MYSQL_NUM&#41;;
    $title = $row&#91;0&#93;;

    echo 'Your title is '.$title;

    mysql_query&#40;'DEALLOCATE PREPARE test_query;',$conn&#41;;
?>
Βέβαια αν υπάρχει εγκατεστημένο το mysqli απλοποιούνται τα πράγματα.

ksamole
Δημοσιεύσεις: 92
Εγγραφή: 08 Οκτ 2006 04:43

Fixing a sql injection

Δημοσίευση από ksamole » 08 Μαρ 2009 23:08

καλυτερα παρατα το mysql και το mysqli και
να χρησιμοποιεις PDO με prepared statements

netpumber
Δημοσιεύσεις: 103
Εγγραφή: 08 Μαρ 2009 19:06

Fixing a sql injection

Δημοσίευση από netpumber » 09 Μαρ 2009 00:07

Δεν θέλω να το παρατήσω.. Θέλω να βρώ με αυτον τον τρόπο λυση... :P για εκπαιδευτικούς σκοπους περισσοτερο..

Άβαταρ μέλους
dva_dev
Script Master
Δημοσιεύσεις: 3790
Εγγραφή: 16 Σεπ 2005 01:32
Επικοινωνία:

Fixing a sql injection

Δημοσίευση από dva_dev » 09 Μαρ 2009 01:14

Αν δεν θέλεις να φύγεις από τις mysql_* κλήσεις δοκίμασε το παράδειγμα και κοίταξε γενικά για prepared statements.

Άβαταρ μέλους
cpulse
Script Master
Δημοσιεύσεις: 1527
Εγγραφή: 21 Μαρ 2006 19:30
Τοποθεσία: Αθήνα village
Επικοινωνία:

Fixing a sql injection

Δημοσίευση από cpulse » 09 Μαρ 2009 14:07

Τα prepared statements είναι ο σωστότερος τρόπος όχι μόνο γιατί αποφεύγονται τα sql injections αλλά και επειδή τα statements μπορούν να γίνουν μία φορά parsed (από την πλευρά του sql server) και σε επαναλαμβανόμενα queries να υπολογίζονται μόνο οι παράμετροι.

Δυστυχώς όμως δεν είναι όμως ρεαλιστικό. Οι περισσότεροι προτιμούν τον λιγότερο κώδικα από τον καλύτερο. Στις εντολές PDO πάντως ο κώδικας είναι μόνο ελάχιστα περισσότερος από τις κλασσικές απλές εντολές.

Σχετικά με την quote_smart() που έχεις netpumber, μοιάζει πολύ με τις εντολές που έχω δει να χρησιμοποιούνται για να καθαρίζουν τα magic quotes. Κάνει ένα recursive call σε περίπτωση που έχεις arrays μέσα στα $_GET και $_POST. Στην περίπτωση σου όμως δεν χρειάζεται γιατί σε ένα sql statement βάζεις strings, integers, floats, όχι arrays.

Επίσης, αν περάσεις το $_GET ή το $_POST από την quote_smart(), μετά όλες οι μεταβλητές τους θα περιέχουν escapings για sql. Αν θελήσεις να χρησιμοποιήσεις κάποια μεταβλητή για ο,τιδήποτε άλλο θα πρέπει να την καθαρίσεις με stripslashes().

Νομίζω είναι αρκετό απλά να γράψεις

Κώδικας: Επιλογή όλων

$result = query&#40;'SELECT name FROM products WHERE id="' . mysql_real_escape_string&#40;$_GET&#91;'id'&#93;&#41; . '"'&#41;; 
ή, πριν να φτάσεις στο query, εφόσων γνωρίζεις οτι το id είναι πάντα αριθμός να κάνεις έναν έλεγχο για το αν περιέχει μόνο αριθμητικά ψηφία

Κώδικας: Επιλογή όλων

if &#40;$_GET&#91;'id'&#93; == '' || !ctype_digit&#40;$_GET&#91;'id'&#93;&#41;&#41;
    die&#40;"Missing/Invalid page parameters"&#41;;

netpumber
Δημοσιεύσεις: 103
Εγγραφή: 08 Μαρ 2009 19:06

Fixing a sql injection

Δημοσίευση από netpumber » 09 Μαρ 2009 20:58

Ευχαριστω παρα πολύ...Θα τα προσπαθήσω όλα... :D :wink:

Άβαταρ μέλους
vassilism
Δημοσιεύσεις: 1950
Εγγραφή: 17 Μαρ 2007 14:47
Επικοινωνία:

Fixing a sql injection

Δημοσίευση από vassilism » 09 Μαρ 2009 22:08

Μιας που συζητάτε για sql injections να ρωτήσω κάτι που το έχω απορία?

Γνωρίζετε αν υπάρχει άλλος τρόπος να περάσει κάποιο sql injection εκτός από την περίπτωση εγγραφής-καταχώρησης μέσα από μια φόρμα?

Άβαταρ μέλους
ThyClub
Honorary Member
Δημοσιεύσεις: 5312
Εγγραφή: 17 Νοέμ 2003 00:21
Τοποθεσία: Hell's Kitchen
Επικοινωνία:

Fixing a sql injection

Δημοσίευση από ThyClub » 09 Μαρ 2009 22:13

Με πολλούς τρόπους πχ Σε κάποια σελίδα που ενημερώνει την βάση για στατιστικά. Πχ μέσω του http_referer string ή μέσω του USER_AGENT string

Άβαταρ μέλους
dva_dev
Script Master
Δημοσιεύσεις: 3790
Εγγραφή: 16 Σεπ 2005 01:32
Επικοινωνία:

Fixing a sql injection

Δημοσίευση από dva_dev » 09 Μαρ 2009 22:18

Σε γενικές γραμμές, σε οποιοδήποτε σημείο διαβάζεις παραμέτρους που στέλνει ο χρήστης και τις χρησιμοποιείς στα queries σου.

Άβαταρ μέλους
vassilism
Δημοσιεύσεις: 1950
Εγγραφή: 17 Μαρ 2007 14:47
Επικοινωνία:

Fixing a sql injection

Δημοσίευση από vassilism » 10 Μαρ 2009 01:39

Επειδή δεν το κατάλαβα ακριβώς, έστω ότι έχω ένα αρχείο με όνομα arxeia.php με τον παρακάτω κώδικα:

Κώδικας: Επιλογή όλων

$query = mysql_query&#40;"SELECT * FROM arxeia"&#41;;

while &#40;$rows = mysql_fetch_array&#40;$query&#41;&#41; 
&#123; 
echo &#40;$rows&#91;'id'&#93;&#41;;
echo &#40;$rows&#91;'onoma_arxeiou'&#93;&#41;;
&#125;
Υπάρχει περίπτωση να περάσουν sql injections?
Επίσης είναι δυνατόν να περάσουν sql injections γράφοντας στην γραμμή διευθύνσεων ενός browser?

Άβαταρ μέλους
Rapid-eraser
WebDev Moderator
Δημοσιεύσεις: 6851
Εγγραφή: 05 Απρ 2003 17:50
Τοποθεσία: Πειραιάς
Επικοινωνία:

Fixing a sql injection

Δημοσίευση από Rapid-eraser » 10 Μαρ 2009 08:47

Όταν δεν περνάς παραμέτρους στο query σου τότε δεν είναι εφικτό το injection.
Πρέπει να συνδέεται με κάποια εξωτερική πηγή πληροφόρησης για να γίνει κάτι τέτοιο.
πχ $_GET $_POST $_COOKIE $_SESION $_REQUEST $_FILES (ο κατάλογος συνεχίζεται με πολλές περιπτώσεις) ... κάτι που έρχεται απέξω.

Έστω ότι έχεις το παρακάτω σενάριο.

Κώδικας: Επιλογή όλων

$query = mysql_query&#40;"SELECT * FROM `arxeia` WHERE `id` = '".$_GET&#91;'id'&#93;."'"&#41;; 
Προφανώς κάποιος πειράζοντας το $_GET['id'] μπορεί να αλλάξει το query πχ.

Κώδικας: Επιλογή όλων

$_GET&#91;'id'&#93; = "3' OR `id` = '4";
Νομίζω γίνεται αυτόματα κατανοητό ότι η εισαγωγή έξτρα πληροφορίας που δεν έχει ελεγχθεί σωστά μπορεί να καταλήξει σε αρκετά προβλήματα.

Πολλές πληροφορίες για τα sql injection θα βρεις εδώ.

Όπως θα δεις για κάθε τύπο sql injection υπάρχει και η κατάλληλη αντιμετώπιση.

Πχ γρήγορα γρήγορα η ίδια η mysql_query αφήνει μόνο ένα query την φορά να εκτελεστεί, οπότε ακόμα και αν κάποιος καταφέρει να περάσει ένα δεύτερο query μέσα στο string σου αυτό δεν θα εκτελεστεί (πιθανότατα !!!).

Μία γενική αρχή που μπορεί να σε προστατέψει είναι ... καμία εξωτερική πηγή πληροφόρησης δεν είναι ασφαλής στο παράδειγμά που σου έδωσα ένα απλό type cast είναι αρκετό για να αποφύγεις το injection και την στιγμή που ξέρεις ότι θες μόνο ένα άρθρο τότε η καλύτερη μορφή του query θα ήταν η εξής

Κώδικας: Επιλογή όλων

$query = mysql_query&#40;"SELECT * FROM `arxeia` WHERE `id` = '".&#40;int&#41;$_GET&#91;'id'&#93;."' LIMIT 1"&#41;; 
Προφανώς το παραπάνω έχει νόημα μόνο όταν το $_GET['id'] είναι ακέραιος αριθμός όπως ένα id αλλά γίνεται τώρα πιο σαφές που είναι το πρόβλημα του ελέγχου
Cu, Rapid-eraser, Tα αγαθά copies κτώνται.
Love is like oxygen, You get too much you get too high
Not enough and you're gonna die, Love gets you high

Άβαταρ μέλους
cherouvim
Script Master
Δημοσιεύσεις: 3137
Εγγραφή: 13 Ιούλ 2005 22:56
Τοποθεσία: Athens, Greece
Επικοινωνία:

Fixing a sql injection

Δημοσίευση από cherouvim » 10 Μαρ 2009 10:17

Τα prepared statements είναι η πιο σίγουρη λύση.

Apostolis_38
Δημοσιεύσεις: 1969
Εγγραφή: 14 Φεβ 2008 16:20
Τοποθεσία: ΠΕΙΡΑΙΑΣ

Fixing a sql injection

Δημοσίευση από Apostolis_38 » 10 Μαρ 2009 10:50

Γιατί;
Κι εκεί δεν χρησιμοποιούνται δεδομένα που δίνει ο χρήστης; π.χ. $_GET.
Απλώς μπαίνουν στο param κι όχι απευθείας στο query.
Παίζει κάποιο ρόλο αυτό;

Άβαταρ μέλους
Rapid-eraser
WebDev Moderator
Δημοσιεύσεις: 6851
Εγγραφή: 05 Απρ 2003 17:50
Τοποθεσία: Πειραιάς
Επικοινωνία:

Fixing a sql injection

Δημοσίευση από Rapid-eraser » 10 Μαρ 2009 12:03

Στο παράδειγμα που έδωσα κάνω type cast στην μεταβλητή αναγκάζοντας την να έρθει σε μορφή (int).

Η μορφή αυτή μετατρέπει τα δεδομένα σε ακέραιο αριθμό που μπορεί να είναι αρνητικός θετικός ή 0.

Ανεξάρτητα δλδ με το τι δεδομένα θα πάρει απέξω η συγκεκριμένη μεταβλητή πάντα κατά την χρίση του type cast θα πάρει την μορφή που του ζητάς.

το "3' and `id` = '2" se int type cast θα μετατραπεί σε 0
το 31.5 ή 31,5 θα μετατραπεί σε 31 ακα.

Όσο για την χρήση των prepared statements θα απαντήσω μόλις βρω χρόνο ώστε να είμαι ακριβής σε αυτά που θέλω να γράψω.
Cu, Rapid-eraser, Tα αγαθά copies κτώνται.
Love is like oxygen, You get too much you get too high
Not enough and you're gonna die, Love gets you high

Απάντηση

Επιστροφή στο “PHP Προγραμματισμός”

Μέλη σε σύνδεση

Μέλη σε αυτήν τη Δ. Συζήτηση: Δεν υπάρχουν εγγεγραμμένα μέλη και 1 επισκέπτης