SQL Injection — ένας τύπος επίθεσης στη βάση δεδομένων της εφαρμογής κατά τον οποίο ο επιτιθέμενος εισάγει κακόβουλο κώδικα SQL στις παραμέτρους του ερωτήματος, αποκτώντας μη εξουσιοδοτημένη πρόσβαση σε δεδομένα ή δυνατότητα τροποποίησής τους. Σύμφωνα με δεδομένα του OWASP (2025), το SQL Injection παραμένει ένα από τα κρίσιμα τρωτά σημεία, ικανό να οδηγήσει σε πλήρη παραβίαση της βάσης δεδομένων. Ένεση κώδικα SQL επιτρέπει στον επιτιθέμενο να διαβάζει, να τροποποιεί και να διαγράφει εγγραφές, και σε ορισμένες περιπτώσεις — να αποκτήσει πρόσβαση στο λειτουργικό σύστημα του διακομιστή.
Κύρια σημεία
Το SQL Injection είναι ένα τρωτό σημείο που προκύπτει όταν η εφαρμογή σχηματίζει ένα ερώτημα SQL μέσω συνένωσης συμβολοσειρών με δεδομένα χρήστη. Ο επιτιθέμενος στέλνει μια ειδικά κατασκευασμένη συμβολοσειρά στην παράμετρο ερωτήματος που αλλάζει τη δομή της εντολής SQL. Αντί να είναι δεδομένα, η εισαγόμενη συμβολοσειρά γίνεται μέρος του κώδικα SQL, επιτρέποντας στον επιτιθέμενο να εκτελεί αυθαίρετα ερωτήματα στη βάση δεδομένων. Σύμφωνα με την Verizon Data Breach Report (2025), το SQL Injection είναι παρόν στο 8% όλων των διερευνημένων διαρροών δεδομένων.
Παρά τη γνωστότητα του τρωτού σημείου (πρώτες αναφορές — τέλη της δεκαετίας του 1990), το SQL Injection εμφανίζεται σε σύγχρονες εφαρμογές. Η αιτία — ανθρώπινος παράγοντας: οι προγραμματιστές επιτρέπουν συνένωση συμβολοσειρών στον κώδικα, ο παλαιός κώδικας δεν αναδιαμορφώνεται και τα πλαίσια ORM χρησιμοποιούνται λανθασμένα (π.χ. ανεπεξέργαστα ερωτήματα με αντικατάσταση τιμών μέσω συμβολοσειρών). Σύμφωνα με δεδομένα της Veracode (2026), περίπου το 14% όλων των σαρωμένων εφαρμογών περιέχει τουλάχιστον ένα τρωτό σημείο SQLi.
Μια επιτυχημένη SQL Injection δίνει στον επιτιθέμενο ένα ευρύ φάσμα δυνατοτήτων: ανάγνωση οποιωνδήποτε πινάκων της βάσης δεδομένων, συμπεριλαμβανομένων των hashes κωδικών πρόσβασης και προσωπικών δεδομένων χρηστών· τροποποίηση και διαγραφή εγγραφών· εκτέλεση διαχειριστικών λειτουργιών (DROP TABLE, TRUNCATE)· σε ορισμένες διαμορφώσεις — απομακρυσμένη εκτέλεση εντολών μέσω xp_cmdshell (MSSQL) ή INTO OUTFILE (MySQL). Συνέπειες — από διαρροή δεδομένων χρηστών έως πλήρη απώλεια ελέγχου του συστήματος.
Οι ενέσεις SQL ταξινομούνται ανάλογα με τον τρόπο εξαγωγής δεδομένων από τη βάση. Η επιλογή της μεθόδου εξαρτάται από το πώς η εφαρμογή επεξεργάζεται τα αποτελέσματα των ερωτημάτων και τα μηνύματα σφάλματος. Ταξινόμηση OWASP διακρίνει τρεις κύριους τύπους: In-band (τα δεδομένα εξάγονται μέσω του ίδιου καναλιού), Inferential/Blind (λογικά συμπεράσματα) και Out-of-band (τα δεδομένα μεταδίδονται μέσω άλλου καναλιού).
| Τύπος | Τρόπος εξαγωγής δεδομένων | Πολυπλοκότητα | Συχνότητα |
|---|---|---|---|
| In-band (κλασικός) | Απευθείας μέσω του αποτελέσματος ερωτήματος | Χαμηλή | Υψηλή |
| Blind SQLi | Λογικά συμπεράσματα βάσει απαντήσεων διακομιστή | Υψηλή | Μεσαία |
| Out-of-band | Μέσω εξωτερικού καναλιού (DNS, HTTP) | Μεσαία | Χαμηλή |
Ο πιο συνηθισμένος τύπος. Ο επιτιθέμενος εισάγει κώδικα SQL στην παράμετρο ερωτήματος και το αποτέλεσμα της ένεσης είναι άμεσα ορατό στην απάντηση του διακομιστή. Δύο υποτύποι: Error-based (μέσω μηνυμάτων σφάλματος βάσης δεδομένων) και UNION-based (μέσω του τελεστή UNION SELECT). Error-based χρησιμοποιεί πληροφορίες από μηνύματα σφάλματος, για παράδειγμα, συντακτικό σφάλμα MySQL που μπορεί να αποκαλύψει το όνομα πίνακα ή τη δομή ερωτήματος. UNION-based επιτρέπει τον συνδυασμό αποτελεσμάτων ενός νόμιμου ερωτήματος με δεδομένα από άλλους πίνακες της βάσης δεδομένων.
Χρησιμοποιείται όταν η εφαρμογή δεν εμφανίζει αποτελέσματα ερωτήματος ή μηνύματα σφάλματος. Ο επιτιθέμενος κάνει ερωτήσεις τύπου "ναι/όχι", στέλνοντας ερωτήματα με λογικές συνθήκες και αναλύοντας τη διαφορά στην απάντηση του διακομιστή (π.χ. χρόνος απόκρισης ή περιεχόμενο σελίδας). Time-based Blind SQLi χρησιμοποιεί συνάρτηση καθυστέρησης (SLEEP, WAITFOR DELAY) για επιβεβαίωση συνθηκών — εάν η σελίδα φορτώνει περισσότερο, η συνθήκη είναι αληθής. Αυτή η μέθοδος είναι πολύ αργή — η εξαγωγή μιας εγγραφής μπορεί να διαρκέσει ώρες.
# Παράδειγμα Blind SQL Injection (time-based)
# Εάν το SQLi είναι ευάλωτο, το SLEEP(2) εκτελείται υπό συνθήκη
import requests
import time
payload = "' OR IF(SUBSTRING((SELECT password FROM users LIMIT 1),1,1)='a',SLEEP(2),0) -- "
url = "http://example.com/user?id=1" + payload
start = time.time()
response = requests.get(url)
elapsed = time.time() - start
# Εάν η απάντηση ήρθε μετά από >2 δευτερόλεπτα — το πρώτο γράμμα του κωδικού είναι 'a'
print(f"Time: {elapsed:.2f}s - First letter is 'a'" if elapsed > 2 else "First letter is not 'a'")
Τα δεδομένα μεταδίδονται όχι μέσω της απάντησης HTTP, αλλά μέσω εναλλακτικών καναλιών: ερωτημάτων DNS, αιτημάτων HTTP σε εξωτερικό διακομιστή, SMTP. Χρησιμοποιείται όταν η εφαρμογή δεν επιστρέφει αποτελέσματα ερωτήματος και δεν εμφανίζει σφάλματα. Η MySQL υποστηρίζει τη συνάρτηση LOAD_FILE(), η οποία μπορεί να εκκινήσει ένα ερώτημα DNS, και η MSSQL — xp_dirtree για αποστολή δεδομένων σε απομακρυσμένο διακομιστή SMB. Το Out-of-band SQL Injection είναι αποτελεσματικό, αλλά απαιτεί πρόσθετες ρυθμίσεις στον διακομιστή του επιτιθέμενου και την παρουσία συγκεκριμένων λειτουργιών βάσης δεδομένων.
Ο μηχανισμός SQL Injection βασίζεται στο γεγονός ότι η SQL χρησιμοποιεί εισαγωγικά για κυριολεκτικά συμβολοσειρών. Εάν η εφαρμογή αντικαθιστά την είσοδο χρήστη απευθείας στο ερώτημα SQL χωρίς διαφυγή, ο επιτιθέμενος μπορεί να "κλείσει" τη συμβολοσειρά και να προσθέσει αυθαίρετο κώδικα SQL. Για παράδειγμα, στο ερώτημα SELECT * FROM users WHERE name = '$input' η αντικατάσταση ' OR '1'='1 μετατρέπει το ερώτημα σε SELECT * FROM users WHERE name = '' OR '1'='1', το οποίο επιστρέφει όλους τους χρήστες.
Εξετάστε μια φόρμα σύνδεσης με το ερώτημα SELECT * FROM users WHERE username = '$user' AND password = '$pass'. Εάν ο επιτιθέμενος εισάγει στο πεδίο username admin' -- και αφήσει τον κωδικό πρόσβασης κενό, το προκύπτον ερώτημα γίνεται SELECT * FROM users WHERE username = 'admin' -- ' AND password = ''. Οι χαρακτήρες -- σχολιάζουν το υπόλοιπο του ερωτήματος και η συνθήκη ελέγχου κωδικού πρόσβασης απενεργοποιείται. Ο διακομιστής επιστρέφει την εγγραφή του χρήστη admin και ο επιτιθέμενος εισέρχεται στο σύστημα χωρίς να γνωρίζει τον κωδικό πρόσβασης.
# Παράδειγμα SQL Injection — παράκαμψη πιστοποίησης
# ΕΥΑΛΩΤΟΣ ΚΩΔΙΚΑΣ: άμεση συνένωση συμβολοσειρών
def login_vulnerable(username, password):
query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
cursor.execute(query)
return cursor.fetchone() is not None
# username = "admin' --" ακυρώνει τον έλεγχο κωδικού
# ΑΣΦΑΛΗΣ ΕΚΔΟΣΗ: παραμετροποιημένο ερώτημα
def login_secure(username, password):
query = "SELECT * FROM users WHERE username = %s AND password = %s"
cursor.execute(query, (username, password))
return cursor.fetchone() is not None
Ο τελεστής UNION SELECT επιτρέπει τον συνδυασμό των αποτελεσμάτων δύο ερωτημάτων SELECT. Εάν ο επιτιθέμενος βρει μια ευάλωτη παράμετρο, προσθέτει UNION SELECT με ερώτημα από άλλο πίνακα. Παράδειγμα: ' UNION SELECT username, password FROM admins --. Προϋπόθεση επιτυχίας — ο αριθμός των στηλών και στα δύο ερωτήματα πρέπει να συμπίπτει. Ο αριθμός στηλών προσδιορίζεται μέσω ORDER BY (αντικατάσταση ' ORDER BY 1--, στη συνέχεια 2, 3... μέχρι σφάλματος). Γνωρίζοντας τον αριθμό στηλών, ο επιτιθέμενος αντικαθιστά UNION SELECT με τον ίδιο αριθμό πεδίων.
Οι κινητές εφαρμογές αντιμετωπίζουν SQL Injection τόσο στην πλευρά του διακομιστή (API) όσο και στην πλευρά του πελάτη — σε τοπικές βάσεις δεδομένων (SQLite, Realm). Αν και ο κίνδυνος SQLi διακομιστή στο κινητό API είναι παρόμοιος με τις διαδικτυακές εφαρμογές, η τοπική βάση δεδομένων δημιουργεί ένα πρόσθετο διάνυσμα. Εάν η εφαρμογή αποθηκεύει δεδομένα σε SQLite και εκτελεί ερωτήματα με συνένωση συμβολοσειρών, κακόβουλα δεδομένα που εισήλθαν στην τοπική βάση δεδομένων μέσω API μπορούν να προκαλέσουν SQLi κατά την επακόλουθη επεξεργασία.
Η τοπική βάση δεδομένων SQLite στη συσκευή είναι επίσης ευάλωτη σε SQL Injection εάν η εφαρμογή σχηματίζει ερωτήματα με συνένωση συμβολοσειρών. Content Providers στο Android και Core Data στο iOS χρησιμοποιούν παραμετροποίηση από προεπιλογή, αλλά τα ανεπεξέργαστα ερωτήματα απαιτούν την προσοχή του προγραμματιστή. Η SQLite δεν υποστηρίζει πολλαπλά ερωτήματα μέσω ερωτηματικού, γεγονός που περιορίζει τις δυνατότητες του επιτιθέμενου, αλλά δεν προστατεύει από την ανάγνωση δεδομένων μέσω συνθηκών WHERE. Χρησιμοποιείτε πάντα selectionArgs στο Android και NSPredicate με παραμέτρους στο iOS.
Το API στο οποίο συνδέεται η κινητή εφαρμογή είναι εξίσου ευάλωτο με οποιονδήποτε διακομιστή ιστού. Οι προγραμματιστές κινητών συχνά θεωρούν ότι το SQLi είναι μόνο πρόβλημα του backend, αλλά το τρωτό σημείο προκύπτει σε επίπεδο τελικού σημείου API που δέχεται παραμέτρους από τον πελάτη. Διαχωρισμός ευθυνών δεν προστατεύει: εάν ο προγραμματιστής backend ξέχασε να παραμετροποιήσει το ερώτημα, η κινητή εφαρμογή του χρήστη γίνεται διάνυσμα επίθεσης. Απαιτήστε από το backend τη χρήση ORM ή prepared statements.
// Παράδειγμα SQL Injection σε τοπικό SQLite σε Android
// ΕΥΑΛΩΤΟΣ ΚΩΔΙΚΑΣ: άμεση συνένωση
fun getUserVulnerable(db: SQLiteDatabase, userId: String): Cursor {
return db.rawQuery(
"SELECT * FROM users WHERE id = $userId", null
)
}
// ΑΣΦΑΛΗΣ ΕΚΔΟΣΗ: παραμετροποίηση μέσω selectionArgs
fun getUserSecure(db: SQLiteDatabase, userId: String): Cursor {
return db.rawQuery(
"SELECT * FROM users WHERE id = ?",
arrayOf(userId)
)
}
Η προστασία από το SQL Injection βασίζεται σε μια απλή αρχή: ποτέ μην εμπιστεύεστε την είσοδο χρήστη σε ερωτήματα SQL. Η μόνη αξιόπιστη μέθοδος — παραμετροποίηση ερωτημάτων (prepared statements), όπου ο κώδικας SQL και τα δεδομένα μεταδίδονται ξεχωριστά. Όλες οι άλλες μέθοδοι — διαφυγή, επικύρωση, WAF — είναι πρόσθετα στρώματα προστασίας, αλλά δεν αντικαθιστούν την παραμετροποίηση. Σύμφωνα με δεδομένα του OWASP (2025), η παραμετροποίηση αποτρέπει το 100% των επιθέσεων SQL Injection.
Κατά τη χρήση prepared statements, το ερώτημα SQL πρώτα μεταγλωττίζεται από τον διακομιστή βάσης δεδομένων χωρίς δεδομένα και στη συνέχεια οι τιμές παραμέτρων μεταδίδονται ξεχωριστά. Η βάση δεδομένων αντιμετωπίζει τις παραμέτρους ως δεδομένα, όχι ως εκτελέσιμο κώδικα. Ακόμη και αν ο επιτιθέμενος στείλει ' OR '1'='1, η βάση δεδομένων το ερμηνεύει ως τιμή συμβολοσειράς, όχι ως κώδικα SQL. Τα prepared statements υποστηρίζονται από όλες τις σύγχρονες γλώσσες και πλαίσια: PDO σε PHP, PreparedStatement σε Java, cursor.execute σε Python.
Τα σύγχρονα ORM (Hibernate, Entity Framework, SQLAlchemy, Room) χρησιμοποιούν αυτόματα παραμετροποίηση κατά την εκτέλεση ερωτημάτων, εκτός εάν ο προγραμματιστής μεταβεί σε ανεπεξέργαστα ερωτήματα. Ωστόσο, το ORM δεν προστατεύει πλήρως: κατασκευές όπως @Query(value = "SELECT * FROM users WHERE name = :name", nativeQuery = true) σε JPA απαιτούν τη μετάδοση παραμέτρων μέσω ονομασμένων παραμέτρων, όχι συνένωση. Οι Query Builders (Knex, jOOQ) επίσης παραμετροποιούν τα ερωτήματα από προεπιλογή, εάν δεν χρησιμοποιούνται ανεπεξέργαστες μέθοδοι.
Η διαφυγή ειδικών χαρακτήρων (mysql_real_escape_string) — μια παλιά μέθοδος που δεν προστατεύει από όλους τους τύπους SQL Injection. Πρόβλημα: η διαφυγή εξαρτάται από την κωδικοποίηση και μπορεί να παρακαμφθεί χρησιμοποιώντας κωδικοποιήσεις πολλών byte (π.χ. GBK σε ασιατικά συστήματα). Χρησιμοποιήστε διαφυγή μόνο σε παλαιό κώδικα όπου η παραμετροποίηση δεν είναι δυνατή, και πάντα σε συνδυασμό με αυστηρή επικύρωση τύπου δεδομένων εισόδου.
| Μέθοδος | Αποτελεσματικότητα | Σύσταση |
|---|---|---|
| Prepared Statements | 100% | Υποχρεωτικό για όλα τα ερωτήματα |
| ORM (σωστή χρήση) | 99% | Συνιστάται |
| Διαφυγή συμβολοσειρών | 70% (εξαρτάται από κωδικοποίηση) | Μόνο παλαιός κώδικας |
| Επικύρωση εισόδου (λευκή λίστα) | 50% (μόνο για αριθμούς) | Πρόσθετο |
| WAF (Web Application Firewall) | 60% | Πρόσθετο |
Ο λογαριασμός της εφαρμογής πρέπει να έχει ελάχιστα απαραίτητα δικαιώματα: SELECT, INSERT, UPDATE, DELETE — μόνο σε πίνακες που πραγματικά χρειάζονται από την εφαρμογή. Απαγορεύστε τη χρήση DROP, TRUNCATE, CREATE για τον λογαριασμό της εφαρμογής. Αυτό θα περιορίσει τη ζημιά ακόμη και σε περίπτωση επιτυχημένου SQL Injection: ο επιτιθέμενος δεν θα μπορεί να διαγράψει πίνακες ή να εκτελέσει διαχειριστικές λειτουργίες.
Ο τακτικός έλεγχος για SQL Injection πρέπει να αποτελεί μέρος του αγωγού ασφαλούς ανάπτυξης. Ο συνδυασμός στατικής ανάλυσης, δυναμικής σάρωσης και χειροκίνητων δοκιμών διείσδυσης δίνει τα καλύτερα αποτελέσματα. Σύμφωνα με την Synopsys Cybersecurity Report (2025), οι αυτόματοι σαρωτές βρίσκουν έως και το 70% των τρωτών σημείων SQLi, αλλά οι σύνθετες επιθέσεις Blind απαιτούν χειροκίνητη δοκιμή.
Για κινητές εφαρμογές, η ανάλυση τοπικού SQLite είναι επίσης σημαντική: ελέγξτε όλες τις κλήσεις rawQuery, ερωτήματα ContentProvider και ερωτήματα Room με rawQuery. Εργαλεία: Android Studio Lint (ανιχνεύει SQLi σε SQLite), MobSF (Mobile Security Framework) για αυτόματη στατική και δυναμική ανάλυση APK/IPA. Συνιστάται επίσης η δοκιμή τελικών σημείων API μέσω sqlmap με παρεμβολή διακομιστή μεσολάβησης της κυκλοφορίας της κινητής εφαρμογής.
Συχνές ερωτήσεις
Το SQL Injection επιτίθεται σε σχεσιακές βάσεις δεδομένων μέσω ερωτημάτων SQL. Το NoSQL Injection επηρεάζει μη σχεσιακές βάσεις δεδομένων (MongoDB, Couchbase) μέσω των τελεστών ερωτημάτων τους ($gte, $ne, $where). Στη MongoDB, η ένεση είναι δυνατή εάν η εφαρμογή σχηματίζει ένα έγγραφο BSON από μια συμβολοσειρά JSON. Οι μηχανισμοί προστασίας είναι παρόμοιοι: παραμετροποίηση και επικύρωση τύπων.
Βρείτε όλα τα σημεία όπου τα ερωτήματα SQL σχηματίζονται μέσω συνένωσης συμβολοσειρών με δεδομένα χρήστη. Αναζητήστε μοτίβα όπως "SELECT ... WHERE id = " + userId ή f"UPDATE ... SET name = '{name}'". Κάθε τέτοια συμβολοσειρά είναι μια δυνητική ένεση SQL. Αντικαταστήστε τα όλα με παραμετροποιημένα ερωτήματα ή prepared statements.
Τα πλαίσια ORM προστατεύουν αυτόματα μόνο εάν χρησιμοποιείτε τις μεθόδους Query Builder και ονομασμένες παραμέτρους τους. Εάν χρησιμοποιείτε ανεπεξέργαστα ερωτήματα (nativeQuery σε JPA, rawQuery σε Room), η προστασία δεν λειτουργεί — πρέπει να μεταδίδετε παραμέτρους μέσω προετοιμασμένων εκφράσεων, όχι μέσω συνένωσης συμβολοσειρών.
Second-Order SQL Injection είναι μια επίθεση κατά την οποία κακόβουλα δεδομένα αποθηκεύονται στη βάση δεδομένων ως ασφαλή αλλά στη συνέχεια χρησιμοποιούνται σε άλλο ερώτημα χωρίς διαφυγή. Για παράδειγμα, ο επιτιθέμενος εγγράφεται με όνομα χρήστη ' OR '1'='1. Τα δεδομένα αποθηκεύονται ως συμβολοσειρά — κατά την εγγραφή δεν υπάρχει επίθεση. Αλλά εάν ένα άλλο ερώτημα αντικαθιστά το όνομα χρήστη στην SQL χωρίς παραμετροποίηση, η ένεση ενεργοποιείται.
Το NoSQL Injection είναι δυνητικά πιο επικίνδυνο λόγω μικρότερης ευαισθητοποίησης των προγραμματιστών. Οι προγραμματιστές γνωρίζουν για το SQL Injection και οι περισσότεροι χρησιμοποιούν ORM, αλλά λίγοι γνωρίζουν για το NoSQL Injection. Στη MongoDB, ένα εσφαλμένα διαμορφωμένο ερώτημα μπορεί να επιστρέψει όλα τα έγγραφα της συλλογής. Προστασία — τα ίδια prepared statements (παραμετροποίηση BSON) και αυστηρή επικύρωση δεδομένων εισόδου.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης