Όταν επιτίθενται σε φόρμες, οι επιτιθέμενοι δεν τις συμπληρώνουν κανονικά. Στέλνουν κώδικα που προσπαθεί να μπει στα συστήματά σου ή να κλέψει δεδομένα. Μπορεί να στείλουν JavaScript που θα τρέξει στον browser των επισκεπτών, εντολές SQL που χαλούν τη βάση δεδομένων ή κακόβουλο περιεχόμενο. Ο έλεγχος εγκυρότητας και το sanitization είναι η άμυνα που σταματά αυτές τις επιθέσεις.
Τι θα μάθεις: τι είναι ο έλεγχος εγκυρότητας και το sanitization, πώς διαφέρουν, πώς δουλεύουν οι επιθέσεις injection, ποιες προστασίες ταιριάζουν σε κάθε τύπο δεδομένων και πώς να τις εφαρμόσεις στις φόρμες σου.
Τι είναι ο έλεγχος εγκυρότητας;
Ο έλεγχος εγκυρότητας (validation) ελέγχει αν τα δεδομένα που στέλνονται στη φόρμα σου έχουν τη μορφή που περιμένεις και τηρούν τους κανόνες σου. Είναι η πρώτη γραμμή άμυνας απέναντι σε κακόβουλα δεδομένα.
Ο έλεγχος απαντά σε ερωτήσεις όπως: είναι αυτό διεύθυνση email ή τυχαίο κείμενο; Είναι αριθμός ή λέξη; Είναι κενό το πεδίο ενώ δεν πρέπει; Έγραψε ο επισκέπτης κάτι που έχει νόημα για το πεδίο ή κάτι ύποπτο;
Παραδείγματα ελέγχων:
- Ένα πεδίο email πρέπει να έχει το σύμβολο @ και ένα domain
- Ένα πεδίο τηλεφώνου πρέπει να έχει μόνο ψηφία και παύλες
- Ένα πεδίο αριθμού δεν πρέπει να έχει γράμματα
- Ένα υποχρεωτικό πεδίο δεν πρέπει να είναι κενό
- Ένα πεδίο κωδικού πρέπει να έχει ελάχιστο μήκος
Ο έλεγχος γίνεται σε δύο σημεία. Στη συσκευή του επισκέπτη λέγεται έλεγχος client-side. Στον server σου λέγεται έλεγχος server-side. Ο client-side δίνει άμεση ειδοποίηση στον επισκέπτη όταν κάνει λάθος. Ο server-side είναι αυτός που προστατεύει πραγματικά από επιθέσεις, γιατί οι επιτιθέμενοι μπορούν να παρακάμψουν τους ελέγχους client-side.
Τι είναι το sanitization;
Το sanitization είναι η διαδικασία που αφαιρεί ή εξουδετερώνει ό,τι είναι επικίνδυνο στα δεδομένα του χρήστη, πριν τα αποθηκεύσεις ή τα επεξεργαστείς. Ακόμα κι αν τα δεδομένα περάσουν τον έλεγχο εγκυρότητας, μπορεί να έχουν κώδικα ή χαρακτήρες που προορίζονται να προκαλέσουν ζημιά.
Παραδείγματα του τι κάνει το sanitization:
- Αφαιρεί ετικέτες HTML όπως `<script>` και `<img>` από τα πεδία κειμένου
- Αφαιρεί ειδικούς χαρακτήρες SQL που θα μπορούσαν να χρησιμοποιηθούν για να παραβιαστεί μια βάση δεδομένων
- Κάνει escape τους ειδικούς χαρακτήρες, ώστε να αντιμετωπίζονται ως κείμενο και όχι ως κώδικας
- Περιορίζει το μήκος των δεδομένων, για να αποφύγεις επιθέσεις buffer overflow
Ο έλεγχος εγκυρότητας και το sanitization δουλεύουν μαζί, αλλά έχουν διαφορετικό σκοπό. Ο έλεγχος εγκυρότητας ελέγχει ότι τα δεδομένα έχουν σωστή μορφή. Το sanitization αφαιρεί ό,τι είναι επικίνδυνο, ακόμα κι αν η μορφή είναι τεχνικά σωστή.
Πώς δουλεύουν οι επιθέσεις injection
SQL injection
Μια επίθεση SQL injection γίνεται όταν ο επιτιθέμενος βάζει κώδικα SQL σε ένα πεδίο φόρμας. Αν ο κώδικας της φόρμας σου δεν κάνει sanitization σε αυτά τα δεδομένα, ο κώδικας SQL εκτελείται στη βάση δεδομένων σου.
Παράδειγμα: μια φόρμα σύνδεσης ζητά διεύθυνση email. Αντί για το email του, ο επιτιθέμενος στέλνει:
' OR '1'='1 Αν η φόρμα σου δεν κάνει sanitization, ο κώδικάς σου μπορεί να τρέξει ένα ερώτημα SQL που μοιάζει έτσι:
SELECT * FROM users WHERE email = '' OR '1'='1' Το κομμάτι `OR '1'='1'` κάνει τη συνθήκη πάντα αληθή, οπότε το ερώτημα επιστρέφει όλους τους χρήστες και όχι μόνο αυτόν με το συγκεκριμένο email. Ο επιτιθέμενος έχει πια παρακάμψει το σύστημα σύνδεσης.
Cross-Site Scripting (XSS)
Μια επίθεση XSS γίνεται όταν ο επιτιθέμενος στέλνει κώδικα JavaScript σε ένα πεδίο φόρμας. Αν η φόρμα δεν κάνει sanitization σε αυτόν τον κώδικα και τον αποθηκεύσει, η JavaScript τρέχει στους browser όσων δουν αργότερα αυτά τα δεδομένα.
Παράδειγμα: μια φόρμα σχολίων δέχεται σχόλια χρηστών. Ο επιτιθέμενος στέλνει:
<script>alert('hacked')</script> Αν αυτό δεν περάσει από sanitization και αποθηκευτεί στη βάση δεδομένων, όποιος ανοίξει την ενότητα σχολίων θα δει να τρέχει η JavaScript και να εμφανίζεται ένα μήνυμα. Μια πιο επικίνδυνη εκδοχή θα μπορούσε να κλέψει cookies, να στείλει τους επισκέπτες σε σελίδα phishing ή να αντλήσει δεδομένα φόρμας.
Command injection
Αν τα δεδομένα της φόρμας σου χρησιμοποιούνται σε εντολές συστήματος (κάτι που συμβαίνει σε ορισμένα backend συστήματα), ο επιτιθέμενος μπορεί να στείλει εντολές του λειτουργικού συστήματος.
Παράδειγμα: ένα πεδίο φόρμας χρησιμοποιείται σε μια εντολή όπως:
ffmpeg -i $filename output.mp4 Αν το `$filename` δεν περάσει από sanitization και ο επιτιθέμενος στείλει `;rm -rf /`, η εντολή γίνεται:
ffmpeg -i ;rm -rf / output.mp4 Η εντολή `rm -rf /` τρέχει και σβήνει αρχεία από το σύστημα. Γι' αυτό οι εντολές συστήματος δεν πρέπει ποτέ να δέχονται δεδομένα χρήστη χωρίς sanitization.
Έλεγχος εγκυρότητας και sanitization ανά τύπο δεδομένων
Διευθύνσεις email
Έλεγχος εγκυρότητας: Έλεγξε ότι το κείμενο ταιριάζει με μοτίβο email (κάτι σαν text@domain.extension). Επιβεβαίωσε ότι έχει μόνο επιτρεπτούς χαρακτήρες.
Sanitization: Αφαίρεσε ετικέτες HTML και ειδικούς χαρακτήρες. Κράτα μόνο γράμματα, αριθμούς, τελείες, παύλες και το σύμβολο @.
Αριθμοί τηλεφώνου
Έλεγχος εγκυρότητας: Έλεγξε ότι περιέχει μόνο ψηφία, παύλες, παρενθέσεις και κενά. Επιβεβαίωσε ότι το μήκος είναι σωστό για τη χώρα που περιμένεις.
Sanitization: Αφαίρεσε κάθε μη αριθμητικό χαρακτήρα εκτός από παύλες και παρενθέσεις. Αφαίρεσε αρχικά μηδενικά ή κενά, αν χρειάζεται.
Πεδία κειμένου (σχόλια, ονόματα, διευθύνσεις)
Έλεγχος εγκυρότητας: Έλεγξε ότι το πεδίο δεν είναι κενό και ότι το μήκος είναι λογικό (όχι εκατομμύρια χαρακτήρες).
Sanitization: Αφαίρεσε ή κάνε escape ετικέτες HTML, JavaScript και ειδικούς χαρακτήρες SQL. Κράτα μόνο απλό κείμενο και βασική στίξη.
Αριθμοί και ποσά
Έλεγχος εγκυρότητας: Έλεγξε ότι η τιμή είναι αριθμός. Για τιμές ή ποσότητες, έλεγξε ότι είναι θετικός αριθμός.
Sanitization: Αφαίρεσε κάθε μη αριθμητικό χαρακτήρα. Αν χρειάζεται, στρογγύλεψε στα σωστά δεκαδικά ψηφία.
Κωδικοί πρόσβασης
Έλεγχος εγκυρότητας: Έλεγξε το ελάχιστο μήκος (τουλάχιστον 8 χαρακτήρες) και, προαιρετικά, ζήτα συνδυασμό κεφαλαίων, πεζών, αριθμών και συμβόλων.
Sanitization: Μην αφαιρείς και μην αλλάζεις κωδικούς. Πρέπει να αποθηκεύονται ακριβώς όπως είναι (με hash, ποτέ ως απλό κείμενο). Αν αφαιρέσεις χαρακτήρες από έναν κωδικό, ο χρήστης δεν θα μπορεί να συνδεθεί.
Μεταφόρτωση αρχείων
Έλεγχος εγκυρότητας: Έλεγξε ότι ο τύπος αρχείου είναι αυτός που περιμένεις (π.χ. μόνο PDF, μόνο εικόνες). Έλεγξε ότι το μέγεθος δεν είναι πολύ μεγάλο.
Sanitization: Μετονόμασε το αρχείο, ώστε οι επιτιθέμενοι να μην μπορούν να χρησιμοποιήσουν ειδικά ονόματα αρχείων. Σάρωσε το αρχείο για malware. Αποθήκευσέ το έξω από τον ριζικό φάκελο του ιστότοπου, ώστε να μη μπορεί να εκτελεστεί ως κώδικας.
Πώς να εφαρμόσεις έλεγχο εγκυρότητας και sanitization
Client-side (στον browser)
Χρησιμοποίησε τα χαρακτηριστικά ελέγχου της HTML5, για να δίνεις άμεση ειδοποίηση στους επισκέπτες:
<input type="email" name="email" required> <input type="tel" name="phone" pattern="[0-9]{10}"> <input type="number" name="age" min="0" max="120"> Αυτό πιάνει τα προφανή λάθη και βελτιώνει την εμπειρία χρήσης. Ωστόσο ο έλεγχος client-side μπορεί να παρακαμφθεί, οπότε από μόνος του δεν είναι μέτρο ασφαλείας.
Server-side (στον server σου)
Εδώ γίνεται η ασφάλεια. Ο κώδικας του backend πρέπει να ελέγχει και να καθαρίζει κάθε δεδομένο:
// Παράδειγμα σε ψευδοκώδικα if (email does not match email pattern) { reject the submission } // Αφαίρεση ετικετών HTML sanitized_comment = remove_html_tags(comment_text) // Escape ειδικών χαρακτήρων για τη βάση δεδομένων safe_name = escape_sql_characters(user_name) // Μόνο τότε αποθήκευσε τα δεδομένα store_in_database(safe_name, sanitized_comment) Χρησιμοποίησε παραμετροποιημένα ερωτήματα για βάσεις δεδομένων
Η καλύτερη άμυνα απέναντι στο SQL injection είναι τα παραμετροποιημένα ερωτήματα (parameterized queries ή prepared statements). Αντί να βάζεις τα δεδομένα του χρήστη κατευθείαν μέσα στο ερώτημα SQL, χρησιμοποιείς placeholders και περνάς τα δεδομένα ξεχωριστά:
// Κακό (ευάλωτο): query = "SELECT * FROM users WHERE email = '" + email + "'" // Καλό (ασφαλές): query = "SELECT * FROM users WHERE email = ?" execute(query, [email]) Με τα παραμετροποιημένα ερωτήματα, ο αναλυτής SQL ξέρει ότι τα δεδομένα του χρήστη είναι δεδομένα και όχι κώδικας. Ακόμα κι αν ο επιτιθέμενος στείλει κώδικα SQL, αντιμετωπίζεται ως απλό κείμενο.
Χρησιμοποίησε βιβλιοθήκες και frameworks
Μη γράφεις κώδικα sanitization από το μηδέν. Χρησιμοποίησε καθιερωμένες βιβλιοθήκες που φτιάχτηκαν γι' αυτόν τον σκοπό. Στην PHP χρησιμοποίησε τη htmlspecialchars() ή μια βιβλιοθήκη όπως η HTML Purifier. Στην Python χρησιμοποίησε το module `html` ή μια βιβλιοθήκη όπως η bleach. Στο Node.js χρησιμοποίησε το `express-validator` ή κάτι αντίστοιχο. Αυτές οι βιβλιοθήκες έχουν δοκιμαστεί και ενημερώνονται για νέους τύπους επιθέσεων.
Συνηθισμένα λάθη στον έλεγχο εγκυρότητας και στο sanitization
Έλεγχος μόνο στο client-side. Ο έλεγχος client-side είναι για την εμπειρία χρήσης, όχι για την ασφάλεια. Ο επιτιθέμενος μπορεί να τον παρακάμψει. Πρέπει να ελέγχεις και στον server.
Μαύρη λίστα επικίνδυνων χαρακτήρων αντί για λευκή λίστα ασφαλών. Αν προσπαθήσεις να μπλοκάρεις το SQL injection αφαιρώντας ερωτηματικά και εισαγωγικά, οι επιτιθέμενοι θα βρουν τρόπο να το παρακάμψουν. Αντί γι' αυτό, βάλε σε λευκή λίστα τους χαρακτήρες που περιμένεις (για τηλέφωνα, μόνο ψηφία και παύλες) και απέρριψε όλα τα υπόλοιπα.
Εμπιστοσύνη στον τύπο δεδομένων του πεδίου. Αν έχεις πεδίο αριθμού, ο browser στέλνει κείμενο που μοιάζει με αριθμό. Ο server σου πρέπει να επαληθεύσει ότι είναι πράγματι αριθμός πριν τον χρησιμοποιήσει. Μην υποθέτεις ποτέ ότι ο τύπος δεδομένων είναι σωστός.
Να ξεχνάς το sanitization στα δεδομένα που εμφανίζονται. Ακόμα κι αν τα δεδομένα αποθηκεύονται με ασφάλεια, αν τα εμφανίσεις σε σελίδα χωρίς escape της HTML, οι επιτιθέμενοι μπορούν να βάλουν κώδικα που τρέχει στον browser των επισκεπτών όταν δουν αυτά τα δεδομένα.
Sanitization με λάθος σειρά. Πρώτα έλεγξε (έχει σωστή μορφή;) και μετά καθάρισε (είναι ασφαλές;). Αν κάνεις πρώτα sanitization και μετά έλεγχο, μπορεί να απορρίψεις δεδομένα που ήταν στην πραγματικότητα ασφαλή.
Φόρμες στο WEMASY
Στον Δημιουργό ιστοσελίδων του WEMASY μπορείς να προσθέσεις φόρμα στην ιστοσελίδα σου. Η επιλογή των πεδίων που θα συλλέγεις είναι δική σου.
Δες τι περιλαμβάνει κάθε πακέτο στη σελίδα τιμών.