By Antithesis Group

SQL injections (μέρος 1ο)

Στο άρθρο θα ασχοληθούμε με τα SQL injections (έγχυση SQL). Τα SQL injections είναι μια διαδεδομένη μέθοδος επίθεσης σε εφαρμογές web που χρησιμοποιούν συστήματα βάσεων δεδομένων.

Με τη μέθοδο των SQL injections κακόβουλοι χρήστες επιδιώκουν να εκμεταλλευτούν ευπάθειες στην ασφαλεία μιας εφαρμογής web, ώστε να επέμβουν στα δεδομένα της βάσης. Ως μέθοδος επίθεσης δεν είναι νέα ούτε πολύπλοκη. Για την εφαρμογή των SQL injections αρκεί απλά ένας web browser και κοινή λογική – έτσι οι επιθέσεις SQL injections εμφανίστηκαν ταυτόχρονα με τις πρώτες εφαρμογές web.

Σε αυτό το πρώτο μέρος του άρθρου θα ασχοληθούμε με την παρουσίαση των SQL injections – τί είναι και πώς γίνονται, με σκοπό την κατανόηση του προβλήματος. Στο δεύτερο μέρος του άρθρου θα δούμε τρόπους αντιμετώπισης του προβλήματος σε διαφορετικές γλώσσες προγραμματισμού, δηλαδή πώς μπορούμε να αποφύγουμε τη συγκεκριμένη ευπάθεια σε εφαρμογές web που αναπτύσσουμε.

Σκοπός των επίθεσεων SQL injections είναι η εκμετάλλευση συγκεκριμένων αδυναμιών μιας εφαρμογής web, ώστε να εκτελεστούν στη βάση δεδομένων επερωτήσεις SQL (SQL queries) που δεν έχουν προβλεφθεί από τους προγραμματιστές.

Παραδείγματα τέτοιων επερωτήσεων είναι η προβολή (SELECT) δεδομένων που δεν έχει προβλεφθεί να προβάλλονται στους χρήστες, η ανεξέλεγκτη εισαγωγή (INSERT) δεδομένων στη βάση και η διαγραφή (DELETE) δεδομένων από τη βάση.

Παρά το αυξημένο ρίσκο, θεωρείται σήμερα μεγάλος ο αριθμός των συστημάτων τα οποία είναι ευάλωτα στις επιθέσεις SQL Injections. Το ευχάριστο είναι ότι ως απειλή εύκολα μπορεί να διερευνηθεί σε μια εφαρμογή και με κατάλληλη πρόβλεψη να αποφευχθεί.

Πως γίνεται;

Στα SQL injections ένας κακόβουλος χρήστης προσπαθεί να εκμεταλλευτεί την ελλιπή ή λανθασμένη επαλήθευση (validation) των δεδομένων εισόδου (input data) μιας εφαρμογής. Τυπικά η ευπάθεια των SQL injections μπορεί να εμφανίζεται και σε μη web εφαρμογές, όμως εκεί είναι σαφώς πιο σπάνιο. Συνήθεις τρόποι όπου οι χρήστες δίνουν δεδομένα εισόδου σε μια εφαρμογή web είναι οι φόρμες (με τις μεθόδους HTTP GET και POST) και τα links (μέθοδος HTTP GET). Στην περίπτωση ελλιπούς επαλήθευσης των δεδομένων εισόδου είναι σε κάποιες περιπτώσεις δυνατόν να περαστούν extra εντολές SQL προς εκτέλεση στην εφαρμογή ή να αλλαχτούν μέρη μιας επερώτησης SQL με τρόπο που δεν έχει προβλεφθεί.

Ας δούμε όμως το πρόβλημα μέσω μερικών πρακτικών παραδειγμάτων (για λόγους απλότητας τα παραδείγματα δίνονται σε PHP):

Παράδειγμα 1

Ας θεωρήσουμε την περίπτωση προβολής στοιχείων ενός υπαλλήλου από έναν πίνακα με όνομα «employees» σε μια βάση δεδομένων MySQL.

Το παρακάτω (ευπαθές) block κώδικα PHP εκτελεί μια επερώτηση SELECT στη βάση δεδομένων, με σκοπό την ανάγνωση από τη βάση δεδομένων των στοιχείων ενός συγκεκριμένου υπαλλήλου.

<?php
$qry = "SELECT employeeid, fullname, salary FROM employees " .
       "WHERE employeeid =" . $_GET['employeeid'];
$result = mysql_query($qry);
?>

Σκοπός του προγραμματιστή εδώ είναι η εκτέλεση επερώτησεων της μορφής:

SELECT employeeid, fullname, salary FROM employees WHERE employeeid = 3
SELECT employeeid, fullname, salary FROM employees WHERE employeeid = 352
SELECT employeeid, fullname, salary FROM employees WHERE employeeid = 590

όπου το employeeid (πρωτεύον κλειδί στον πίνακα employees) είναι τιμή που δίνεται στην πράξη από τον χρήστη της εφαρμογής (μέσω του browser, με χρήση της μεθόδου GET του HTTP). Για παράδειγμα, στην τυπική περίπτωση, το employeeid μπορεί να δίνεται με ένα link της μορφής:

http://www.example.com/employees.php?employeeid=3

Το πρόβλημα είναι ότι η τιμή της παραμέτρου GET «employeeid» που δίνεται στο URL, ΔΕΝ επαληθεύεται επαρκώς πριν την εκτέλεση της επερώτησης από τον κώδικα.

Έτσι ένας κακόβουλος χρήστης μπορεί να γράψει το εξής URL (χειρονακτικά) στον browser:

http://www.example.com/employees.php?employeeid=3 OR 1=1

όπου θα έχει ως αποτέλεσμα να εκτελεστεί στη βάση δεδομένων η εξής επερώτηση:

SELECT employeeid, fullname, salary FROM employees WHERE employeeid=3 OR 1=1

έτσι όμως ο κλάδος WHERE θα ισχύει για κάθε εγγραφή του πίνακα employees, οπότε επιστρέφονται όλες οι εγγραφές στη μεταβλητή $result.

Ανάλογα με το πως χρησιμοποιείται λοιπόν στη συνέχεια η μεταβλητή $result (ώστε να παρουσιάσει τα δεδομένα στους χρήστες της web εφαρμογής), ενδέχεται ο κακόβουλος χρήστης να δει πληροφορίες που δεν είναι σκόπιμο.

,

Παράδειγμα 2

Ας δούμε το εξής (ευπαθές) block κώδικα PHP για login σε μια εφαρμογή, όπου χρησιμοποιούνται οι τιμές που δίνουν οι χρήστες σε μια web φόρμα (username και password) για την είσοδο τους στο σύστημα:

<?php
$username = $_POST['username'];
$password = $_POST['password'];
$qry = "SELECT userid FROM users" .
       " WHERE username='$username' AND password='$password'";
$result = mysql_query($qry);
if (mysql_numrows($result) > 0) {
    //log in user...
}
?>

Οι τιμές username και password δίνονται με χρήση μιας τυπικής web login φόρμας (με τη μέθοδο HTTP POST). Αν ο κακόβουλος χρήστης στο password πεδίο δώσει την τιμή:

bar' OR 1=1 OR username='

τότε από τον παραπάνω κώδικα PHP έχουμε την εκτέλεση της επερώτησης:

SELECT userid FROM users WHERE 
username='foo' AND password='bar' OR 1=1 OR username='';

η οποία όμως ισχύει για κάθε εγγραφή του πίνακα (αφού πάντοτε 1=1) και έτσι το $result θα έχει πάντοτε εγγραφές, ανεξάρτητα από το τι έχει εισαχθεί στα πεδία username και password. Στη συνέχεια η μεταβλητή $results ελέγχεται για το αν περιέχει εγγραφές (που με τον τρόπο αυτόν θα περιέχει), τότε κάνει login τον χρήστη.

Έτσι ενδέχεται η πρόσβαση στην εφαρμογή (login) από άτομα που δεν είναι εξουσιοδοτημένα για κάτι τέτοιο.

Σε αυτό το παράδειγμα και στο προηγούμενο, είδαμε πως ένας κακόβουλος χρήστης μπορεί να προσπαθήσει να αλλάξει μια SQL επερώτηση με τρόπο που δεν έχει προβλεφθεί από τον προγραμματιστή. Φυσικά η επερώτηση θα μπορούσε να αλλαχθεί με διαφορετικούς τρόπους από ότι στα συγκεκριμένα παραδείγματα (τυπική περίπτωση είναι για παράδειγμα η προσπάθεια χρήσης κλάδων UNION της SQL).

Παράδειγμα 3

Το παράδειγμα αυτό, εκμεταλλεύεται τη δυνατότητα εκτέλεση πολλαπλών εντολών SQL ως μια επερώτηση στο σύστημα. Οι εντολές διαχωρίζονται μεταξύ τους με τον χαρακτήρα ; (semicolon – ελληνικό ερωτηματικό). Η εκτέλεση πολλαπλών εντολών ως μια επερώτηση είναι μια standard δυνατότητα στο χώρο των βάσεων δεδομένων, όμως αποτελεί τον μεγαλύτερο κίνδυνο στην περίπτωση των SQL Injections.

Θα βασιστούμε στο παράδειγμα 1 και θα θεωρήσουμε ότι το σύστημα βάσεων δεδομένων είναι η PostgreSQL. Έχουμε το εξής (ευπαθές) block κώδικα:

<?php
$qry = "SELECT employeeid, fullname, salary FROM employees " .
       "WHERE employeeid =" . $_GET['employeeid'];
$result = pg_query($qry);
?>

ο προγραμματιστής αναμένει δεδομένα εισόδου από links της μορφής:

http://www.example.com/employees.php?employeeid=3

που θα έχει ως αποτέλεσμα την εκτέλεση της επερώτησης:

SELECT employeeid, fullname, salary FROM employees
WHERE employeeid = 3

αυτή τη φορά όμως ο κακόβουλος χρήστης δίνει την εξής URL (χειρονακτικά) στον browser:

http://www.example.com/employees.php?employeeid=3;DELETE FROM users;

και έτσι θα εκτελεστούν οι εξής 2 εντολές στην κλήση της pg_query():

SELECT employeeid, fullname, salary FROM employees
WHERE employeeid = 3;
DELETE FROM users;

όπου θα έχει ως αποτέλεσμα να διαγραφούν όλα τα δεδομένα του πίνακα users από τη βάση!

Φυσικά αντί του DELETE του παραδείγματος, οποιαδήποτε άλλη SQL εντολή θα μπορούσε στην περίπτωση αυτή να εκτελεστεί (και αυτό είναι και ένα καλό παράδειγμα του γιατί δεν είναι ασφαλές να συνδέεται η εφαρμογή μας στη βάση δεδομένων με τα στοιχεία ενός χρήστη της βάσης που έχει αυξημένα δικαιώματα πρόσβασης – με αυξημένα δικαιώματα πρόσβασης κάποιος θα μπορούσε να διαγράψει έως και άλλες βάσεις δεδομένων του συστήματος μη σχετιζόμενες με τη συγκεκριμένη εφαρμογή web).

Είναι η MySQL ευάλωτη στην εκτέλεση πολλαπλών εντολών; Άλλα συστήματα βάσεων δεδομένων;

Μέχρι την έκδοση 4.1 της MySQL δεν ήταν δυνατή η εκτέλεση πολλαπλών εντολών ως μια επερώτηση μέσω γλωσσών προγραμματισμού. Από την έκδοση 4.1 και μετά προστέθηκε η δυνατότητα αυτή. Η γλώσσα προγραμματισμού PHP επέλεξε να εξακολουθήσει να μην υποστηρίζει πολλαπλές εντολές διαχωρισμένες με ; στη συνάρτηση mysql_query().

Η μη υποστήριξη πολλαπλών εντολών ως μια επερώτηση στην PHP αποτελεί στην ουσία αδυναμία της γλώσσας, αφού η εκτέλεση πολλαπλών εντολών προσφέρει μεγαλύτερη ταχύτητα και είναι σε αρκετές περιπτώσεις επιθυμητή, όπως σε μαζικά UPDATE και μαζικά INSERT. Ασφάλεια έναντι επιθέσεων SQL injections οφείλει να έχει ο κώδικας μια εφαρμογής και είναι ευθύνη του προγραμματιστή. Στην PHP5 το mysqli interface (mysql improved interface) υποστηρίζει πολλαπλές εντολές με τη μέθοδο multi_query().

Οι περισσότερες γλώσσες προγραμματισμού (όπως οι Perl, Java, Python, C) προσφέρουν τη δυνατότητα πολλαπλών εντολών για εκδόσεις MySQL 4.1+. Σε αρκετές περιπτώσεις πρέπει κατά τη σύνδεση στη βάση να ενεργοποιηθεί η υποστήριξη αυτή. Για παράδειγμα, στην περίπτωση του JDBC της Java, πρέπει η σύνδεση να γίνει με το εξής DSN:

«jdbc:mysql://127.0.0.1:3306/databasename?allowMultiQueries=true»

ενώ στο DBI της Perl, έχουμε αντίστοιχα:

«DBI:mysql:databasename;host=127.0.0.1;port=3306;mysql_multi_statements=1»

Σε άλλα συστήματα βάσεων δεδομένων (εκτός της MySQL, όπως για παράδειγμα οι: SQLite, PostgreSQL, Oracle, MS SQL Server) υποστηρίζεται κανονικά η εκτέλεση πολλαπλών εντολών (και από τις γλώσσες PHP 4 και PHP 5).

Εδώ ολοκληρώνεται η συνοπτική παρουσίαση των ευπαθειών SQL injections. Έγινε μια προσπάθεια να περιγραφεί το πρόβλημα μέσω μερικών χαρακτηριστικών απλών παραδειγμάτων. Στα 2 πρώτα παραδείγματα είδαμε μεθόδους αλλαγής μιας επερώτησης SQL ενώ στο τρίτο παράδειγμα είδαμε πως είναι δυνατόν να περαστούν νέες ολοκληρωμένες εντολές SQL προς εκτέλεση.

Στο 2ο μέρος του άρθρου θα εξετάσουμε τρόπους ώστε να αποφεύγονται αυτές οι ευπάθειες στις εφαρμογές web, για διάφορες γλώσσες προγραμματισμού.

Creative Commons Άδεια
Αυτό το έργο, εκτός αν έχει ρητώς διατυπωθεί διαφορετικά, εκδίδεται υπό μία Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 Άδεια.

4 Σχόλια στο “SQL injections (μέρος 1ο)”


By rentacar. 13 Ιουλίου 2011 at 18:04

πολύ καλο άρθρο για ένα πολύ σοβαρό θέμα ευχαριστούμε

By Γιάννης. 11 Ιανουαρίου 2012 at 20:24

Πολύ ωραίο άρθρο,απλό και κατανοητό.
Περιμένω και το δεύτερο μέρος.

By Michael Dimitriou. 26 Σεπτεμβρίου 2012 at 12:21

Πολύ κατανοητό!

By μαθηματα wordpress. 16 Ιανουαρίου 2015 at 22:37

Πολυ χρησιμο αρθρο. Καλυτερα για την αναπτυξη των εφαρμογων μας να χρησιμοποιουμε καποιο framework(yii, laravel κλπ)

Ανενεργό

Το openspot δεν είναι πλέον ενεργό

Το openspot λειτούργησε από το 2006 έως το 2012.
Εξακολουθεί να επιτρέπει την πλοήγηση στο περιεχόμενό του.