Nette Documentation Preview

syntax
Το Latte είναι συνώνυμο της ασφάλειας
*************************************

<div class=perex>

Το Latte είναι το μοναδικό σύστημα διαμόρφωσης προτύπων PHP με αποτελεσματική προστασία από την κρίσιμη ευπάθεια Cross-site Scripting (XSS). Αυτό επιτυγχάνεται χάρη στη λεγόμενη context-sensitive escaping. Ας μιλήσουμε,

- ποια είναι η αρχή της ευπάθειας XSS και γιατί είναι τόσο επικίνδυνη
- τι κάνει το Latte τόσο αποτελεσματικό στην άμυνα κατά του XSS
- γιατί το Twig, το Blade και άλλα πρότυπα μπορούν να παραβιαστούν εύκολα

</div>


Cross-Site Scripting (XSS) .[#toc-cross-site-scripting-xss]
===========================================================

Το Cross-site Scripting (XSS για συντομία) είναι μία από τις πιο κοινές ευπάθειες σε ιστότοπους και μάλιστα πολύ επικίνδυνη. Επιτρέπει σε έναν εισβολέα να εισάγει ένα κακόβουλο σενάριο (που ονομάζεται κακόβουλο λογισμικό) σε έναν ξένο ιστότοπο, το οποίο εκτελείται στο πρόγραμμα περιήγησης ενός ανυποψίαστου χρήστη.

Τι μπορεί να κάνει ένα τέτοιο script; Για παράδειγμα, μπορεί να στείλει αυθαίρετο περιεχόμενο από τον παραβιασμένο ιστότοπο στον επιτιθέμενο, συμπεριλαμβανομένων ευαίσθητων δεδομένων που εμφανίζονται μετά τη σύνδεση. Μπορεί να τροποποιήσει τη σελίδα ή να κάνει άλλα αιτήματα εκ μέρους του χρήστη.
Για παράδειγμα, αν επρόκειτο για webmail, θα μπορούσε να διαβάσει ευαίσθητα μηνύματα, να τροποποιήσει το εμφανιζόμενο περιεχόμενο ή να αλλάξει τις ρυθμίσεις, π.χ. να ενεργοποιήσει την προώθηση αντιγράφων όλων των μηνυμάτων στη διεύθυνση του επιτιθέμενου για να αποκτήσει πρόσβαση σε μελλοντικά μηνύματα ηλεκτρονικού ταχυδρομείου.

Αυτός είναι και ο λόγος για τον οποίο το XSS βρίσκεται στην κορυφή της λίστας των πιο επικίνδυνων ευπαθειών. Εάν ανακαλυφθεί μια ευπάθεια σε έναν ιστότοπο, θα πρέπει να αφαιρεθεί το συντομότερο δυνατό για να αποτραπεί η εκμετάλλευση.


Πώς προκύπτει η ευπάθεια; .[#toc-how-does-the-vulnerability-arise]
------------------------------------------------------------------

Το σφάλμα εμφανίζεται στο σημείο όπου δημιουργείται η ιστοσελίδα και εκτυπώνονται οι μεταβλητές. Φανταστείτε ότι δημιουργείτε μια σελίδα αναζήτησης και στην αρχή θα υπάρχει μια παράγραφος με τον όρο αναζήτησης στη μορφή:

```php
echo '<p>Search results for <em>' . $search . '</em></p>';
```

Ένας εισβολέας μπορεί να γράψει οποιαδήποτε συμβολοσειρά, συμπεριλαμβανομένου κώδικα HTML όπως `<script>alert("Hacked!")</script>`, στο πεδίο αναζήτησης και συνεπώς στη μεταβλητή `$search`. Δεδομένου ότι η έξοδος δεν καθαρίζεται με κανέναν τρόπο, γίνεται μέρος της εμφανιζόμενης σελίδας:

```html
<p>Search results for <em><script>alert("Hacked!")</script></em></p>
```

Αντί για την έξοδο της συμβολοσειράς αναζήτησης, το πρόγραμμα περιήγησης εκτελεί JavaScript. Και έτσι ο επιτιθέμενος καταλαμβάνει τη σελίδα.

Θα μπορούσατε να ισχυριστείτε ότι η τοποθέτηση κώδικα σε μια μεταβλητή θα εκτελέσει πράγματι τη JavaScript, αλλά μόνο στο πρόγραμμα περιήγησης του επιτιθέμενου. Πώς φτάνει στο θύμα; Από αυτή την άποψη, μπορούμε να διακρίνουμε διάφορους τύπους XSS. Στο παράδειγμά μας για τη σελίδα αναζήτησης, μιλάμε για *reflected XSS*.
Σε αυτή την περίπτωση, το θύμα πρέπει να εξαπατηθεί ώστε να κάνει κλικ σε έναν σύνδεσμο που περιέχει κακόβουλο κώδικα στην παράμετρο:

```
https://example.com/?search=<script>alert("Hacked!")</script>
```

Παρόλο που απαιτείται κάποια κοινωνική μηχανική για να κάνει ο χρήστης να αποκτήσει πρόσβαση στο σύνδεσμο, δεν είναι δύσκολο. Οι χρήστες κάνουν κλικ σε συνδέσμους, είτε σε μηνύματα ηλεκτρονικού ταχυδρομείου είτε σε μέσα κοινωνικής δικτύωσης, χωρίς πολλή σκέψη. Και το γεγονός ότι υπάρχει κάτι ύποπτο στη διεύθυνση μπορεί να συγκαλυφθεί από τον συντομευτή URL, ώστε ο χρήστης να βλέπει μόνο το `bit.ly/xxx`.

Ωστόσο, υπάρχει μια δεύτερη και πολύ πιο επικίνδυνη μορφή επίθεσης, γνωστή ως *stored XSS* ή *persistent XSS*, όπου ο επιτιθέμενος καταφέρνει να αποθηκεύσει κακόβουλο κώδικα στον διακομιστή, ώστε να εισάγεται αυτόματα σε ορισμένες σελίδες.

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

Φαίνεται ότι το νόημα της επίθεσης είναι να πάρει ο `<script>` συμβολοσειρά στη σελίδα. Στην πραγματικότητα, "υπάρχουν πολλοί τρόποι για την ενσωμάτωση της JavaScript":https://cheatsheetseries.owasp.org/cheatsheets/XSS_Filter_Evasion_Cheat_Sheet.html.
Ας πάρουμε ένα παράδειγμα ενσωμάτωσης με τη χρήση ενός χαρακτηριστικού HTML. Ας έχουμε μια γκαλερί φωτογραφιών όπου μπορείτε να εισάγετε μια λεζάντα στις εικόνες, η οποία εκτυπώνεται στο χαρακτηριστικό `alt`:

```php
echo '<img src="' . $imageFile . '" alt="' . $imageAlt . '">';
```

Ένας επιτιθέμενος χρειάζεται απλώς να εισάγει ένα έξυπνα κατασκευασμένο αλφαριθμητικό `" onload="alert('Hacked!')` ως ετικέτα, και αν η έξοδος δεν καθαριστεί, ο κώδικας που θα προκύψει θα μοιάζει με αυτό:

```html
<img src="photo0145.webp" alt="" onload="alert('Hacked!')">
```

Το ψεύτικο χαρακτηριστικό `onload` γίνεται τώρα μέρος της σελίδας. Το πρόγραμμα περιήγησης θα εκτελέσει τον κώδικα που περιέχει μόλις γίνει λήψη της εικόνας. Hacked!


Πώς να αμυνθείτε κατά του XSS; .[#toc-how-to-defend-against-xss]
----------------------------------------------------------------

Οποιαδήποτε προσπάθεια ανίχνευσης μιας επίθεσης με τη χρήση μιας μαύρης λίστας, όπως ο αποκλεισμός της `<script>` συμβολοσειράς, κ.λπ. Η βάση μιας λειτουργικής άμυνας είναι η **συνεχής απομάκρυνση όλων των δεδομένων που εκτυπώνονται μέσα στη σελίδα**.

Πρώτα απ' όλα, αυτό περιλαμβάνει την αντικατάσταση όλων των χαρακτήρων με ειδική σημασία με άλλες ταιριαστές ακολουθίες, η οποία ονομάζεται **escaping** στην αργκό (ο πρώτος χαρακτήρας της ακολουθίας ονομάζεται χαρακτήρας διαφυγής, εξ ου και το όνομα).
Για παράδειγμα, στο κείμενο HTML, ο χαρακτήρας `<` has a special meaning, which, if it is not to be interpreted as the beginning of a tag, must be replaced by a visually corresponding sequence, the so-called HTML entity `&lt;`.
Και το πρόγραμμα περιήγησης εκτυπώνει έναν χαρακτήρα.

**Είναι πολύ σημαντικό να διακρίνουμε το πλαίσιο στο οποίο εξάγονται τα δεδομένα**. Επειδή διαφορετικά πλαίσια καθαρίζουν διαφορετικά τις συμβολοσειρές. Διαφορετικοί χαρακτήρες έχουν ειδική σημασία σε διαφορετικά πλαίσια.
Για παράδειγμα, η διαφυγή σε κείμενο HTML, σε χαρακτηριστικά HTML, μέσα σε κάποια ειδικά στοιχεία κ.λπ. είναι διαφορετική. Θα το συζητήσουμε αυτό λεπτομερώς σε λίγο.

Είναι καλύτερο να εκτελείτε την αποφυγή απευθείας όταν η συμβολοσειρά γράφεται στη σελίδα, διασφαλίζοντας ότι γίνεται πραγματικά και μόνο μία φορά. Είναι καλύτερο αν η επεξεργασία γίνεται **αυτόματα** απευθείας από το σύστημα διαμόρφωσης προτύπων.
Διότι αν η επεξεργασία δεν γίνεται αυτόματα, ο προγραμματιστής μπορεί να την ξεχάσει. Και μια παράλειψη σημαίνει ότι ο ιστότοπος είναι ευάλωτος.

Ωστόσο, το XSS δεν επηρεάζει μόνο την έξοδο των δεδομένων στα templates, αλλά και άλλα μέρη της εφαρμογής που πρέπει να χειρίζονται σωστά τα μη αξιόπιστα δεδομένα. Για παράδειγμα, τα JavaScript στην εφαρμογή σας δεν πρέπει να χρησιμοποιούν το `innerHTML` σε συνδυασμό με αυτά, αλλά μόνο το `innerText` ή το `textContent`.
Ιδιαίτερη προσοχή πρέπει να δίνεται στις συναρτήσεις που αξιολογούν συμβολοσειρές όπως η JavaScript, η οποία είναι `eval()`, αλλά και `setTimeout()`, ή στη χρήση `setAttribute()` με χαρακτηριστικά συμβάντων όπως `onload`, κ.λπ. Αλλά αυτό ξεφεύγει από το πεδίο εφαρμογής που καλύπτουν τα πρότυπα.

**Η ιδανική άμυνα 3 σημείων:**

1) Αναγνωρίστε το πλαίσιο στο οποίο εξάγονται τα δεδομένα
2) Εξυγίανση των δεδομένων σύμφωνα με τους κανόνες αυτού του πλαισίου (δηλ. "επίγνωση του πλαισίου")
3) το κάνει αυτό αυτόματα


Διαφυγή με επίγνωση του πλαισίου .[#toc-context-aware-escaping]
===============================================================

Τι ακριβώς εννοείται με τη λέξη πλαίσιο; Είναι ένα μέρος του εγγράφου με τους δικούς του κανόνες για την αντιμετώπιση των δεδομένων που πρόκειται να εξαχθούν. Εξαρτάται από τον τύπο του εγγράφου (HTML, XML, CSS, JavaScript, απλό κείμενο, ...) και μπορεί να διαφέρει σε συγκεκριμένα μέρη του εγγράφου.
Για παράδειγμα, σε ένα έγγραφο HTML, υπάρχουν πολλά τέτοια μέρη (contexts) όπου ισχύουν πολύ διαφορετικοί κανόνες. Μπορεί να εκπλαγείτε από το πόσοι είναι αυτοί. Ακολουθούν οι τέσσερις πρώτοι:

```html
<p>#text</p>
<img src="#attribute">
<textarea>#rawtext</textarea>
<!-- #comment -->
```

Το αρχικό και βασικό πλαίσιο μιας σελίδας HTML είναι το κείμενο HTML. Ποιοι είναι οι κανόνες εδώ; Οι χαρακτήρες ειδικής σημασίας `<` and `&` αντιπροσωπεύουν την αρχή μιας ετικέτας ή μιας οντότητας, οπότε πρέπει να τους αποφύγουμε αντικαθιστώντας τους με την οντότητα HTML (`<` with `&lt;`, `&` with `&amp`).

Το δεύτερο πιο συνηθισμένο πλαίσιο είναι η τιμή ενός χαρακτηριστικού HTML. Διαφέρει από το κείμενο στο ότι η ειδική σημασία εδώ πηγαίνει στα εισαγωγικά `"` or `'` που οριοθετούν το χαρακτηριστικό. Αυτό πρέπει να γράφεται ως οντότητα, ώστε να μη θεωρείται ως το τέλος του χαρακτηριστικού.
Από την άλλη πλευρά, ο χαρακτήρας `&lt;` μπορεί να χρησιμοποιηθεί με ασφάλεια σε ένα χαρακτηριστικό επειδή δεν έχει καμία ειδική σημασία εδώ- δεν μπορεί να εκληφθεί ως αρχή μιας ετικέτας ή ενός σχολίου.
Αλλά προσέξτε, στην HTML μπορείτε να γράψετε τιμές χαρακτηριστικών χωρίς εισαγωγικά, οπότε μια ολόκληρη σειρά χαρακτήρων έχουν ειδική σημασία, οπότε πρόκειται για ένα άλλο ξεχωριστό πλαίσιο.

Μπορεί να σας εκπλήξει, αλλά ισχύουν ειδικοί κανόνες μέσα στο `<textarea>` και `<title>` στοιχεία, όπου το `<` character need not (but can) be escaped unless followed by `/`. Αλλά αυτό είναι περισσότερο μια περιέργεια.

Είναι ενδιαφέρον μέσα στα σχόλια της HTML. Εδώ, οι οντότητες HTML δεν χρησιμοποιούνται για την αποφυγή. Δεν υπάρχει καμία προδιαγραφή που να ορίζει καν πώς να αποφεύγεται η διαφυγή στα σχόλια.
Απλά πρέπει να ακολουθήσετε τους κάπως "περίεργους κανόνες":https://html.spec.whatwg.org/multipage/syntax.html#comments και να αποφύγετε ορισμένους συνδυασμούς χαρακτήρων σε αυτά.

Τα περιεχόμενα μπορούν επίσης να είναι πολυεπίπεδα, κάτι που συμβαίνει όταν ενσωματώνουμε JavaScript ή CSS σε HTML. Αυτό μπορεί να γίνει με δύο διαφορετικούς τρόπους, ανά στοιχείο ή ανά χαρακτηριστικό:

```html
<script>#js-element</script>
<img onclick="#js-attribute">

<style>#css-element</style>
<p style="#css-attribute"></p>
```

Δύο τρόποι και δύο διαφορετικά είδη διαφυγής δεδομένων. Μέσα στο `<script>` και `<style>` στοιχείων, όπως στην περίπτωση των σχολίων HTML, δεν πραγματοποιείται διαφυγή με χρήση οντοτήτων HTML. Κατά την αποφυγή δεδομένων μέσα σε αυτά τα στοιχεία, υπάρχει μόνο ένας κανόνας: το κείμενο δεν πρέπει να περιέχει την ακολουθία `</script` και `</style` αντίστοιχα.

Από την άλλη πλευρά, τα χαρακτηριστικά `style` και `on***` αποφεύγονται με τη χρήση οντοτήτων HTML.

Και, φυσικά, μέσα σε ενσωματωμένη JavaScript ή CSS, ισχύουν οι κανόνες διαφυγής αυτών των γλωσσών. Έτσι, μια συμβολοσειρά σε ένα χαρακτηριστικό όπως το `onload` αποφεύγεται πρώτα σύμφωνα με τους κανόνες του JS και στη συνέχεια σύμφωνα με τους κανόνες των χαρακτηριστικών HTML.

Ugh... Όπως καταλαβαίνετε, η HTML είναι ένα πολύ σύνθετο έγγραφο με επίπεδα πλαισίων, και χωρίς να ξέρω ακριβώς πού βγάζω τα δεδομένα (δηλαδή σε ποιο πλαίσιο), δεν μπορώ να πω πώς θα το κάνω σωστά.


Θέλετε ένα παράδειγμα; .[#toc-do-you-want-an-example]
-----------------------------------------------------

Ας έχουμε μια συμβολοσειρά `Rock'n'Roll`.

Αν το εξάγετε σε κείμενο HTML, δεν χρειάζεται να κάνετε καμία αντικατάσταση σε αυτή την περίπτωση, επειδή η συμβολοσειρά δεν περιέχει κανένα χαρακτήρα με ειδική σημασία. Η κατάσταση είναι διαφορετική αν το γράψετε μέσα σε ένα χαρακτηριστικό HTML που περικλείεται σε μονά εισαγωγικά. Σε αυτή την περίπτωση, πρέπει να αποφύγετε τα εισαγωγικά σε οντότητες HTML:

```html
<div title='Rock&apos;n&apos;Roll'></div>
```

Αυτό ήταν εύκολο. Μια πολύ πιο ενδιαφέρουσα κατάσταση συμβαίνει όταν το πλαίσιο είναι πολυεπίπεδο, για παράδειγμα αν η συμβολοσειρά είναι μέρος της JavaScript.

Έτσι, πρώτα το γράφουμε μέσα στην ίδια τη JavaScript. Δηλαδή, το τυλίγουμε σε εισαγωγικά και ταυτόχρονα αποφεύγουμε τα εισαγωγικά που περιέχονται σε αυτό χρησιμοποιώντας τον χαρακτήρα `\`:

```js
'Rock\'n\'Roll'
```

Μπορούμε να προσθέσουμε μια κλήση συνάρτησης για να κάνουμε τον κώδικα να κάνει κάτι:

```js
alert('Rock\'n\'Roll');
```

Αν εισάγουμε αυτόν τον κώδικα σε ένα έγγραφο HTML χρησιμοποιώντας `<script>`, δεν χρειάζεται να τροποποιήσουμε τίποτα άλλο, επειδή δεν υπάρχει η απαγορευμένη ακολουθία `</script`:

```html
<script> alert('Rock\'n\'Roll'); </script>
```

Ωστόσο, αν θέλουμε να τον εισάγουμε σε ένα χαρακτηριστικό HTML, θα πρέπει ακόμα να αποφύγουμε τα εισαγωγικά σε οντότητες HTML:

```html
<div onclick='alert(&apos;Rock\&apos;n\&apos;Roll&apos;)'></div>
```

Ωστόσο, το εμφωλευμένο πλαίσιο δεν χρειάζεται να είναι μόνο JS ή CSS. Είναι επίσης συνήθως μια διεύθυνση URL. Οι παράμετροι στα URL αποφεύγονται μετατρέποντας τους ειδικούς χαρακτήρες σε ακολουθίες που ξεκινούν με `%`. Παράδειγμα:

```
https://example.org/?a=Jazz&b=Rock%27n%27Roll
```

Και όταν εξάγουμε αυτή τη συμβολοσειρά σε ένα χαρακτηριστικό, εξακολουθούμε να εφαρμόζουμε escaping σύμφωνα με αυτό το πλαίσιο και να αντικαθιστούμε το `&` with `&amp`:

```html
<a href="https://example.org/?a=Jazz&amp;b=Rock%27n%27Roll">
```

Αν διαβάσατε μέχρι εδώ, συγχαρητήρια, ήταν κουραστικό. Τώρα έχετε μια καλή ιδέα για το τι είναι τα συμφραζόμενα και το escaping. Και δεν χρειάζεται να ανησυχείτε ότι είναι περίπλοκο. Το Latte το κάνει αυτό για εσάς αυτόματα.


Latte vs Naive Systems .[#toc-latte-vs-naive-systems]
=====================================================

Δείξαμε πώς να αποφεύγετε σωστά τα δεδομένα σε ένα έγγραφο HTML και πόσο κρίσιμο είναι να γνωρίζετε το πλαίσιο, δηλαδή το πού βγάζετε τα δεδομένα. Με άλλα λόγια, πώς λειτουργεί το context sensitive escaping.
Αν και αυτό είναι απαραίτητη προϋπόθεση για τη λειτουργική άμυνα XSS, **Το Latte είναι το μόνο σύστημα template για την PHP που το κάνει αυτό**.

Πώς είναι αυτό δυνατόν όταν όλα τα συστήματα σήμερα ισχυρίζονται ότι διαθέτουν αυτόματη διαφυγή;
Η αυτόματη διαφυγή χωρίς γνώση του πλαισίου είναι μια μαλακία που **δημιουργεί μια ψευδή αίσθηση ασφάλειας**.

Τα συστήματα δημιουργίας προτύπων όπως το Twig, το Laravel Blade και άλλα δεν βλέπουν καμία δομή HTML στο πρότυπο. Επομένως, δεν βλέπουν ούτε τα συμφραζόμενα. Σε σύγκριση με το Latte, είναι τυφλά και αφελή. Χειρίζονται μόνο τη δική τους σήμανση, όλα τα άλλα είναι μια άσχετη ροή χαρακτήρων γι' αυτά:

<div class="juxtapose juxtapose--dark-handle" data-startingposition="80" data-animation="juxtapose-wiper">

```twig .{file:Twig template as seen by Twig himself}
░░░░░░░░░░░░░░░░░{{ text }}░░░░░░░
░░░░░░░░░░░░░░░░{{ text }}░░░░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ text }}░░░░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ text }}░░░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ text }}░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ text }}░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ text }}░░░░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ text }}░░░░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ text }}░░░░░░░░░░░
░░░░░░░░░░░░░░░░░░░{{ text }}░░░░
```

```twig .{file:Twig template as the designer sees it}
- in text: <span>{{ text }}</span>
- in tag: <span {{ text }} ></span>
- in attribute: <span title='{{ text }}'></span>
- in unquoted attribute: <span title={{ text }}></span>
- in attribute containing URL: <a href="{{ text }}"></a>
- in attribute containing JavaScript: <img onload="{{ text }}">
- in attribute containing CSS: <span style="{{ text }}"></span>
- in JavaScriptu: <script>var = {{ text }}</script>
- in CSS: <style>body { content: {{ text }}; }</style>
- in comment: <!-- {{ text }} -->
```

</div>

Τα αφελή συστήματα μετατρέπουν μηχανικά τους χαρακτήρες `< > & ' "` σε οντότητες HTML, που είναι ένας έγκυρος τρόπος διαφυγής στις περισσότερες χρήσεις, αλλά όχι πάντα. Έτσι, δεν μπορούν να ανιχνεύσουν ή να αποτρέψουν διάφορα κενά ασφαλείας, όπως θα δείξουμε παρακάτω.

Η Latte βλέπει το πρότυπο με τον ίδιο τρόπο που το βλέπετε κι εσείς. Κατανοεί την HTML, την XML, αναγνωρίζει τις ετικέτες, τα χαρακτηριστικά κ.λπ. Και εξαιτίας αυτού, κάνει διάκριση μεταξύ των πλαισίων και αντιμετωπίζει τα δεδομένα ανάλογα. Έτσι, προσφέρει πραγματικά αποτελεσματική προστασία από την κρίσιμη ευπάθεια Cross-site Scripting.


Ζωντανή επίδειξη .[#toc-live-demonstration]
===========================================

Στα αριστερά μπορείτε να δείτε το πρότυπο στο Latte, ενώ στα δεξιά είναι ο παραγόμενος κώδικας HTML. Η μεταβλητή `$text` εξάγεται αρκετές φορές, κάθε φορά σε ελαφρώς διαφορετικό πλαίσιο. Και ως εκ τούτου διαφυλάσσεται λίγο διαφορετικά. Μπορείτε να επεξεργαστείτε τον κώδικα του προτύπου μόνοι σας, για παράδειγμα να αλλάξετε το περιεχόμενο της μεταβλητής κ.λπ. Δοκιμάστε το:

<div class="grid fiddle wiki-expanded">
<div class="contains-pre">

``` .{file:template.latte; min-height: 14em}[fiddle-source]
{* TRY TO EDIT THIS TEMPLATE *}
{var $text = "Rock'n'Roll"}
- <span>{$text}</span>
- <span title='{$text}'></span>
- <span title={$text}></span>
- <img onload="{$text}">
- <script>var = {$text}</script>
- <!-- {$text} -->
```

</div>

<div class="contains-pre">

``` .{file:view-source:...; min-height: 14em}[fiddle-output]
- <span>Rock'n'Roll</span>
- <span title='Rock&apos;n&apos;Roll'></span>
- <span title="Rock&apos;n&apos;Roll"></span>
- <img onload="&quot;Rock&apos;n&apos;Roll&quot;">
- <script>var = "Rock'n'Roll"</script>
- <!-- Rock'n'Roll -->
```

</div>
</div>

Δεν είναι υπέροχο! Το Latte κάνει αυτόματα τη διαφυγή με ευαισθησία περιβάλλοντος, έτσι ώστε ο προγραμματιστής:

- δεν χρειάζεται να σκέφτεται ή να γνωρίζει πώς να αποφεύγει δεδομένα
- δεν μπορεί να κάνει λάθος
- δεν μπορεί να το ξεχάσει

Αυτά δεν είναι καν όλα τα συμφραζόμενα που διακρίνει η Latte κατά την εξαγωγή και για τα οποία προσαρμόζει την επεξεργασία των δεδομένων. Θα εξετάσουμε τώρα περισσότερες ενδιαφέρουσες περιπτώσεις.


Πώς να χακάρετε τα αφελή συστήματα .[#toc-how-to-hack-naive-systems]
====================================================================

Θα χρησιμοποιήσουμε μερικά πρακτικά παραδείγματα για να δείξουμε πόσο σημαντική είναι η διαφοροποίηση του πλαισίου και γιατί τα αφελή συστήματα templating δεν παρέχουν επαρκή προστασία έναντι του XSS, σε αντίθεση με το Latte.
Στα παραδείγματα θα χρησιμοποιήσουμε το Twig ως εκπρόσωπο ενός αφελούς συστήματος, αλλά το ίδιο ισχύει και για άλλα συστήματα.


Ευπάθεια χαρακτηριστικών .[#toc-attribute-vulnerability]
--------------------------------------------------------

Ας προσπαθήσουμε να εισάγουμε κακόβουλο κώδικα στη σελίδα χρησιμοποιώντας το χαρακτηριστικό HTML όπως [δείξαμε παραπάνω |#How does the vulnerability arise]. Ας έχουμε ένα πρότυπο στο Twig που εμφανίζει μια εικόνα:

```twig .{file:Twig}
<img src={{ imageFile }} alt={{ imageAlt }}>
```

Σημειώστε ότι δεν υπάρχουν εισαγωγικά γύρω από τις τιμές του χαρακτηριστικού. Ο κωδικοποιητής μπορεί να τα ξέχασε, κάτι που απλά συμβαίνει. Για παράδειγμα, στο React, ο κώδικας γράφεται έτσι, χωρίς εισαγωγικά, και ένας προγραμματιστής που αλλάζει γλώσσα μπορεί εύκολα να ξεχάσει τα εισαγωγικά.

Ο επιτιθέμενος εισάγει ένα έξυπνα κατασκευασμένο αλφαριθμητικό `foo onload=alert('Hacked!')` ως λεζάντα εικόνας. Γνωρίζουμε ήδη ότι το Twig δεν μπορεί να καταλάβει αν μια μεταβλητή εκτυπώνεται σε μια ροή κειμένου HTML, μέσα σε ένα χαρακτηριστικό, μέσα σε ένα σχόλιο HTML κ.ο.κ. Με λίγα λόγια, δεν κάνει διάκριση μεταξύ των πλαισίων. Και απλά μετατρέπει μηχανικά τους χαρακτήρες `< > & ' "` σε οντότητες HTML.
Έτσι, ο κώδικας που θα προκύψει θα μοιάζει ως εξής:

```html
<img src=photo0145.webp alt=foo onload=alert(&#039;Hacked!&#039;)>
```

**Δημιουργήθηκε ένα κενό ασφαλείας!**

Ένα ψεύτικο χαρακτηριστικό `onload` έχει γίνει μέρος της σελίδας και το πρόγραμμα περιήγησης το εκτελεί αμέσως μετά τη λήψη της εικόνας.

Ας δούμε τώρα πώς χειρίζεται το ίδιο πρότυπο η Latte:

```latte .{file:Latte}
<img src={$imageFile} alt={$imageAlt}>
```

Latte βλέπει το πρότυπο με τον ίδιο τρόπο που το βλέπετε εσείς. Σε αντίθεση με το Twig, καταλαβαίνει την HTML και γνωρίζει ότι μια μεταβλητή εκτυπώνεται ως τιμή χαρακτηριστικού που δεν είναι σε εισαγωγικά. Γι' αυτό και τα προσθέτει. Όταν ένας επιτιθέμενος εισάγει την ίδια λεζάντα, ο κώδικας που προκύπτει θα μοιάζει κάπως έτσι:

```html
<img src="photo0145.webp" alt="foo onload=alert(&apos;Hacked!&apos;)">
```

**Το latte απέτρεψε επιτυχώς το XSS.**


Εκτύπωση μιας μεταβλητής σε JavaScript .[#toc-printing-a-variable-in-javascript]
--------------------------------------------------------------------------------

Χάρη στη διαφυγή με ευαισθησία περιβάλλοντος, είναι δυνατή η χρήση μεταβλητών της PHP εγγενώς μέσα στη JavaScript.

```latte
<p onclick="alert({$movie})">{$movie}</p>

<script>var movie = {$movie};</script>
```

Εάν η μεταβλητή `$movie` αποθηκεύει το αλφαριθμητικό `'Amarcord & 8 1/2'`, παράγει την ακόλουθη έξοδο. Παρατηρήστε τη διαφορετική διαφυγή που χρησιμοποιείται στην HTML και τη JavaScript, καθώς και στο χαρακτηριστικό `onclick`:

```latte
<p onclick="alert(&quot;Amarcord &amp; 8 1\/2&quot;)">Amarcord &amp; 8 1/2</p>

<script>var movie = "Amarcord & 8 1\/2";</script>
```


Έλεγχος συνδέσμου .[#toc-link-checking]
---------------------------------------

Το Latte ελέγχει αυτόματα αν η μεταβλητή που χρησιμοποιείται στα χαρακτηριστικά `src` ή `href` περιέχει μια διεύθυνση URL στο διαδίκτυο (δηλαδή πρωτόκολλο HTTP) και αποτρέπει τη συγγραφή συνδέσμων που μπορεί να αποτελέσουν κίνδυνο για την ασφάλεια.

```latte
{var $link = 'javascript:attack()'}

<a href={$link}>click here</a>
```

Γράφει:

```latte
<a href="">click here</a>
```

Ο έλεγχος μπορεί να απενεργοποιηθεί χρησιμοποιώντας το φίλτρο [nocheck |filters#nocheck].


Όρια του Latte .[#toc-limits-of-latte]
======================================

Το Latte δεν αποτελεί πλήρη προστασία XSS για ολόκληρη την εφαρμογή. Θα μας δυσαρεστούσε αν σταματούσατε να σκέφτεστε την ασφάλεια όταν χρησιμοποιείτε το Latte.
Ο στόχος του Latte είναι να διασφαλίσει ότι ένας επιτιθέμενος δεν μπορεί να αλλάξει τη δομή μιας σελίδας, να αλλοιώσει στοιχεία ή χαρακτηριστικά HTML. Δεν ελέγχει όμως την ορθότητα του περιεχομένου των δεδομένων που εξάγονται. Ή την ορθότητα της συμπεριφοράς της JavaScript.
Αυτό είναι πέρα από το πεδίο εφαρμογής του συστήματος διαμόρφωσης προτύπων. Η επαλήθευση της ορθότητας των δεδομένων, ειδικά αυτών που εισάγονται από τον χρήστη και συνεπώς δεν είναι αξιόπιστα, είναι ένα σημαντικό έργο για τον προγραμματιστή.

Το Latte είναι συνώνυμο της ασφάλειας

Το Latte είναι το μοναδικό σύστημα διαμόρφωσης προτύπων PHP με αποτελεσματική προστασία από την κρίσιμη ευπάθεια Cross-site Scripting (XSS). Αυτό επιτυγχάνεται χάρη στη λεγόμενη context-sensitive escaping. Ας μιλήσουμε,

  • ποια είναι η αρχή της ευπάθειας XSS και γιατί είναι τόσο επικίνδυνη
  • τι κάνει το Latte τόσο αποτελεσματικό στην άμυνα κατά του XSS
  • γιατί το Twig, το Blade και άλλα πρότυπα μπορούν να παραβιαστούν εύκολα

Cross-Site Scripting (XSS)

Το Cross-site Scripting (XSS για συντομία) είναι μία από τις πιο κοινές ευπάθειες σε ιστότοπους και μάλιστα πολύ επικίνδυνη. Επιτρέπει σε έναν εισβολέα να εισάγει ένα κακόβουλο σενάριο (που ονομάζεται κακόβουλο λογισμικό) σε έναν ξένο ιστότοπο, το οποίο εκτελείται στο πρόγραμμα περιήγησης ενός ανυποψίαστου χρήστη.

Τι μπορεί να κάνει ένα τέτοιο script; Για παράδειγμα, μπορεί να στείλει αυθαίρετο περιεχόμενο από τον παραβιασμένο ιστότοπο στον επιτιθέμενο, συμπεριλαμβανομένων ευαίσθητων δεδομένων που εμφανίζονται μετά τη σύνδεση. Μπορεί να τροποποιήσει τη σελίδα ή να κάνει άλλα αιτήματα εκ μέρους του χρήστη. Για παράδειγμα, αν επρόκειτο για webmail, θα μπορούσε να διαβάσει ευαίσθητα μηνύματα, να τροποποιήσει το εμφανιζόμενο περιεχόμενο ή να αλλάξει τις ρυθμίσεις, π.χ. να ενεργοποιήσει την προώθηση αντιγράφων όλων των μηνυμάτων στη διεύθυνση του επιτιθέμενου για να αποκτήσει πρόσβαση σε μελλοντικά μηνύματα ηλεκτρονικού ταχυδρομείου.

Αυτός είναι και ο λόγος για τον οποίο το XSS βρίσκεται στην κορυφή της λίστας των πιο επικίνδυνων ευπαθειών. Εάν ανακαλυφθεί μια ευπάθεια σε έναν ιστότοπο, θα πρέπει να αφαιρεθεί το συντομότερο δυνατό για να αποτραπεί η εκμετάλλευση.

Πώς προκύπτει η ευπάθεια;

Το σφάλμα εμφανίζεται στο σημείο όπου δημιουργείται η ιστοσελίδα και εκτυπώνονται οι μεταβλητές. Φανταστείτε ότι δημιουργείτε μια σελίδα αναζήτησης και στην αρχή θα υπάρχει μια παράγραφος με τον όρο αναζήτησης στη μορφή:

echo '<p>Search results for <em>' . $search . '</em></p>';

Ένας εισβολέας μπορεί να γράψει οποιαδήποτε συμβολοσειρά, συμπεριλαμβανομένου κώδικα HTML όπως <script>alert("Hacked!")</script>, στο πεδίο αναζήτησης και συνεπώς στη μεταβλητή $search. Δεδομένου ότι η έξοδος δεν καθαρίζεται με κανέναν τρόπο, γίνεται μέρος της εμφανιζόμενης σελίδας:

<p>Search results for <em><script>alert("Hacked!")</script></em></p>

Αντί για την έξοδο της συμβολοσειράς αναζήτησης, το πρόγραμμα περιήγησης εκτελεί JavaScript. Και έτσι ο επιτιθέμενος καταλαμβάνει τη σελίδα.

Θα μπορούσατε να ισχυριστείτε ότι η τοποθέτηση κώδικα σε μια μεταβλητή θα εκτελέσει πράγματι τη JavaScript, αλλά μόνο στο πρόγραμμα περιήγησης του επιτιθέμενου. Πώς φτάνει στο θύμα; Από αυτή την άποψη, μπορούμε να διακρίνουμε διάφορους τύπους XSS. Στο παράδειγμά μας για τη σελίδα αναζήτησης, μιλάμε για reflected XSS. Σε αυτή την περίπτωση, το θύμα πρέπει να εξαπατηθεί ώστε να κάνει κλικ σε έναν σύνδεσμο που περιέχει κακόβουλο κώδικα στην παράμετρο:

https://example.com/?search=<script>alert("Hacked!")</script>

Παρόλο που απαιτείται κάποια κοινωνική μηχανική για να κάνει ο χρήστης να αποκτήσει πρόσβαση στο σύνδεσμο, δεν είναι δύσκολο. Οι χρήστες κάνουν κλικ σε συνδέσμους, είτε σε μηνύματα ηλεκτρονικού ταχυδρομείου είτε σε μέσα κοινωνικής δικτύωσης, χωρίς πολλή σκέψη. Και το γεγονός ότι υπάρχει κάτι ύποπτο στη διεύθυνση μπορεί να συγκαλυφθεί από τον συντομευτή URL, ώστε ο χρήστης να βλέπει μόνο το bit.ly/xxx.

Ωστόσο, υπάρχει μια δεύτερη και πολύ πιο επικίνδυνη μορφή επίθεσης, γνωστή ως stored XSS ή persistent XSS, όπου ο επιτιθέμενος καταφέρνει να αποθηκεύσει κακόβουλο κώδικα στον διακομιστή, ώστε να εισάγεται αυτόματα σε ορισμένες σελίδες.

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

Φαίνεται ότι το νόημα της επίθεσης είναι να πάρει ο <script> συμβολοσειρά στη σελίδα. Στην πραγματικότητα, υπάρχουν πολλοί τρόποι για την ενσωμάτωση της JavaScript. Ας πάρουμε ένα παράδειγμα ενσωμάτωσης με τη χρήση ενός χαρακτηριστικού HTML. Ας έχουμε μια γκαλερί φωτογραφιών όπου μπορείτε να εισάγετε μια λεζάντα στις εικόνες, η οποία εκτυπώνεται στο χαρακτηριστικό alt:

echo '<img src="' . $imageFile . '" alt="' . $imageAlt . '">';

Ένας επιτιθέμενος χρειάζεται απλώς να εισάγει ένα έξυπνα κατασκευασμένο αλφαριθμητικό " onload="alert('Hacked!') ως ετικέτα, και αν η έξοδος δεν καθαριστεί, ο κώδικας που θα προκύψει θα μοιάζει με αυτό:

<img src="photo0145.webp" alt="" onload="alert('Hacked!')">

Το ψεύτικο χαρακτηριστικό onload γίνεται τώρα μέρος της σελίδας. Το πρόγραμμα περιήγησης θα εκτελέσει τον κώδικα που περιέχει μόλις γίνει λήψη της εικόνας. Hacked!

Πώς να αμυνθείτε κατά του XSS;

Οποιαδήποτε προσπάθεια ανίχνευσης μιας επίθεσης με τη χρήση μιας μαύρης λίστας, όπως ο αποκλεισμός της <script> συμβολοσειράς, κ.λπ. Η βάση μιας λειτουργικής άμυνας είναι η συνεχής απομάκρυνση όλων των δεδομένων που εκτυπώνονται μέσα στη σελίδα.

Πρώτα απ' όλα, αυτό περιλαμβάνει την αντικατάσταση όλων των χαρακτήρων με ειδική σημασία με άλλες ταιριαστές ακολουθίες, η οποία ονομάζεται escaping στην αργκό (ο πρώτος χαρακτήρας της ακολουθίας ονομάζεται χαρακτήρας διαφυγής, εξ ου και το όνομα). Για παράδειγμα, στο κείμενο HTML, ο χαρακτήρας < has a special meaning, which, if it is not to be interpreted as the beginning of a tag, must be replaced by a visually corresponding sequence, the so-called HTML entity &lt;. Και το πρόγραμμα περιήγησης εκτυπώνει έναν χαρακτήρα.

Είναι πολύ σημαντικό να διακρίνουμε το πλαίσιο στο οποίο εξάγονται τα δεδομένα. Επειδή διαφορετικά πλαίσια καθαρίζουν διαφορετικά τις συμβολοσειρές. Διαφορετικοί χαρακτήρες έχουν ειδική σημασία σε διαφορετικά πλαίσια. Για παράδειγμα, η διαφυγή σε κείμενο HTML, σε χαρακτηριστικά HTML, μέσα σε κάποια ειδικά στοιχεία κ.λπ. είναι διαφορετική. Θα το συζητήσουμε αυτό λεπτομερώς σε λίγο.

Είναι καλύτερο να εκτελείτε την αποφυγή απευθείας όταν η συμβολοσειρά γράφεται στη σελίδα, διασφαλίζοντας ότι γίνεται πραγματικά και μόνο μία φορά. Είναι καλύτερο αν η επεξεργασία γίνεται αυτόματα απευθείας από το σύστημα διαμόρφωσης προτύπων. Διότι αν η επεξεργασία δεν γίνεται αυτόματα, ο προγραμματιστής μπορεί να την ξεχάσει. Και μια παράλειψη σημαίνει ότι ο ιστότοπος είναι ευάλωτος.

Ωστόσο, το XSS δεν επηρεάζει μόνο την έξοδο των δεδομένων στα templates, αλλά και άλλα μέρη της εφαρμογής που πρέπει να χειρίζονται σωστά τα μη αξιόπιστα δεδομένα. Για παράδειγμα, τα JavaScript στην εφαρμογή σας δεν πρέπει να χρησιμοποιούν το innerHTML σε συνδυασμό με αυτά, αλλά μόνο το innerText ή το textContent. Ιδιαίτερη προσοχή πρέπει να δίνεται στις συναρτήσεις που αξιολογούν συμβολοσειρές όπως η JavaScript, η οποία είναι eval(), αλλά και setTimeout(), ή στη χρήση setAttribute() με χαρακτηριστικά συμβάντων όπως onload, κ.λπ. Αλλά αυτό ξεφεύγει από το πεδίο εφαρμογής που καλύπτουν τα πρότυπα.

Η ιδανική άμυνα 3 σημείων:

  1. Αναγνωρίστε το πλαίσιο στο οποίο εξάγονται τα δεδομένα
  2. Εξυγίανση των δεδομένων σύμφωνα με τους κανόνες αυτού του πλαισίου (δηλ. „επίγνωση του πλαισίου“)
  3. το κάνει αυτό αυτόματα

Διαφυγή με επίγνωση του πλαισίου

Τι ακριβώς εννοείται με τη λέξη πλαίσιο; Είναι ένα μέρος του εγγράφου με τους δικούς του κανόνες για την αντιμετώπιση των δεδομένων που πρόκειται να εξαχθούν. Εξαρτάται από τον τύπο του εγγράφου (HTML, XML, CSS, JavaScript, απλό κείμενο, …) και μπορεί να διαφέρει σε συγκεκριμένα μέρη του εγγράφου. Για παράδειγμα, σε ένα έγγραφο HTML, υπάρχουν πολλά τέτοια μέρη (contexts) όπου ισχύουν πολύ διαφορετικοί κανόνες. Μπορεί να εκπλαγείτε από το πόσοι είναι αυτοί. Ακολουθούν οι τέσσερις πρώτοι:

<p>#text</p>
<img src="#attribute">
<textarea>#rawtext</textarea>
<!-- #comment -->

Το αρχικό και βασικό πλαίσιο μιας σελίδας HTML είναι το κείμενο HTML. Ποιοι είναι οι κανόνες εδώ; Οι χαρακτήρες ειδικής σημασίας < and & αντιπροσωπεύουν την αρχή μιας ετικέτας ή μιας οντότητας, οπότε πρέπει να τους αποφύγουμε αντικαθιστώντας τους με την οντότητα HTML (< with &lt;, & with &amp).

Το δεύτερο πιο συνηθισμένο πλαίσιο είναι η τιμή ενός χαρακτηριστικού HTML. Διαφέρει από το κείμενο στο ότι η ειδική σημασία εδώ πηγαίνει στα εισαγωγικά " or ' που οριοθετούν το χαρακτηριστικό. Αυτό πρέπει να γράφεται ως οντότητα, ώστε να μη θεωρείται ως το τέλος του χαρακτηριστικού. Από την άλλη πλευρά, ο χαρακτήρας &lt; μπορεί να χρησιμοποιηθεί με ασφάλεια σε ένα χαρακτηριστικό επειδή δεν έχει καμία ειδική σημασία εδώ- δεν μπορεί να εκληφθεί ως αρχή μιας ετικέτας ή ενός σχολίου. Αλλά προσέξτε, στην HTML μπορείτε να γράψετε τιμές χαρακτηριστικών χωρίς εισαγωγικά, οπότε μια ολόκληρη σειρά χαρακτήρων έχουν ειδική σημασία, οπότε πρόκειται για ένα άλλο ξεχωριστό πλαίσιο.

Μπορεί να σας εκπλήξει, αλλά ισχύουν ειδικοί κανόνες μέσα στο <textarea> και <title> στοιχεία, όπου το < character need not (but can) be escaped unless followed by /. Αλλά αυτό είναι περισσότερο μια περιέργεια.

Είναι ενδιαφέρον μέσα στα σχόλια της HTML. Εδώ, οι οντότητες HTML δεν χρησιμοποιούνται για την αποφυγή. Δεν υπάρχει καμία προδιαγραφή που να ορίζει καν πώς να αποφεύγεται η διαφυγή στα σχόλια. Απλά πρέπει να ακολουθήσετε τους κάπως περίεργους κανόνες και να αποφύγετε ορισμένους συνδυασμούς χαρακτήρων σε αυτά.

Τα περιεχόμενα μπορούν επίσης να είναι πολυεπίπεδα, κάτι που συμβαίνει όταν ενσωματώνουμε JavaScript ή CSS σε HTML. Αυτό μπορεί να γίνει με δύο διαφορετικούς τρόπους, ανά στοιχείο ή ανά χαρακτηριστικό:

<script>#js-element</script>
<img onclick="#js-attribute">

<style>#css-element</style>
<p style="#css-attribute"></p>

Δύο τρόποι και δύο διαφορετικά είδη διαφυγής δεδομένων. Μέσα στο <script> και <style> στοιχείων, όπως στην περίπτωση των σχολίων HTML, δεν πραγματοποιείται διαφυγή με χρήση οντοτήτων HTML. Κατά την αποφυγή δεδομένων μέσα σε αυτά τα στοιχεία, υπάρχει μόνο ένας κανόνας: το κείμενο δεν πρέπει να περιέχει την ακολουθία </script και </style αντίστοιχα.

Από την άλλη πλευρά, τα χαρακτηριστικά style και on*** αποφεύγονται με τη χρήση οντοτήτων HTML.

Και, φυσικά, μέσα σε ενσωματωμένη JavaScript ή CSS, ισχύουν οι κανόνες διαφυγής αυτών των γλωσσών. Έτσι, μια συμβολοσειρά σε ένα χαρακτηριστικό όπως το onload αποφεύγεται πρώτα σύμφωνα με τους κανόνες του JS και στη συνέχεια σύμφωνα με τους κανόνες των χαρακτηριστικών HTML.

Ugh… Όπως καταλαβαίνετε, η HTML είναι ένα πολύ σύνθετο έγγραφο με επίπεδα πλαισίων, και χωρίς να ξέρω ακριβώς πού βγάζω τα δεδομένα (δηλαδή σε ποιο πλαίσιο), δεν μπορώ να πω πώς θα το κάνω σωστά.

Θέλετε ένα παράδειγμα;

Ας έχουμε μια συμβολοσειρά Rock'n'Roll.

Αν το εξάγετε σε κείμενο HTML, δεν χρειάζεται να κάνετε καμία αντικατάσταση σε αυτή την περίπτωση, επειδή η συμβολοσειρά δεν περιέχει κανένα χαρακτήρα με ειδική σημασία. Η κατάσταση είναι διαφορετική αν το γράψετε μέσα σε ένα χαρακτηριστικό HTML που περικλείεται σε μονά εισαγωγικά. Σε αυτή την περίπτωση, πρέπει να αποφύγετε τα εισαγωγικά σε οντότητες HTML:

<div title='Rock&apos;n&apos;Roll'></div>

Αυτό ήταν εύκολο. Μια πολύ πιο ενδιαφέρουσα κατάσταση συμβαίνει όταν το πλαίσιο είναι πολυεπίπεδο, για παράδειγμα αν η συμβολοσειρά είναι μέρος της JavaScript.

Έτσι, πρώτα το γράφουμε μέσα στην ίδια τη JavaScript. Δηλαδή, το τυλίγουμε σε εισαγωγικά και ταυτόχρονα αποφεύγουμε τα εισαγωγικά που περιέχονται σε αυτό χρησιμοποιώντας τον χαρακτήρα \:

'Rock\'n\'Roll'

Μπορούμε να προσθέσουμε μια κλήση συνάρτησης για να κάνουμε τον κώδικα να κάνει κάτι:

alert('Rock\'n\'Roll');

Αν εισάγουμε αυτόν τον κώδικα σε ένα έγγραφο HTML χρησιμοποιώντας <script>, δεν χρειάζεται να τροποποιήσουμε τίποτα άλλο, επειδή δεν υπάρχει η απαγορευμένη ακολουθία </script:

<script> alert('Rock\'n\'Roll'); </script>

Ωστόσο, αν θέλουμε να τον εισάγουμε σε ένα χαρακτηριστικό HTML, θα πρέπει ακόμα να αποφύγουμε τα εισαγωγικά σε οντότητες HTML:

<div onclick='alert(&apos;Rock\&apos;n\&apos;Roll&apos;)'></div>

Ωστόσο, το εμφωλευμένο πλαίσιο δεν χρειάζεται να είναι μόνο JS ή CSS. Είναι επίσης συνήθως μια διεύθυνση URL. Οι παράμετροι στα URL αποφεύγονται μετατρέποντας τους ειδικούς χαρακτήρες σε ακολουθίες που ξεκινούν με %. Παράδειγμα:

https://example.org/?a=Jazz&b=Rock%27n%27Roll

Και όταν εξάγουμε αυτή τη συμβολοσειρά σε ένα χαρακτηριστικό, εξακολουθούμε να εφαρμόζουμε escaping σύμφωνα με αυτό το πλαίσιο και να αντικαθιστούμε το & with &amp:

<a href="https://example.org/?a=Jazz&amp;b=Rock%27n%27Roll">

Αν διαβάσατε μέχρι εδώ, συγχαρητήρια, ήταν κουραστικό. Τώρα έχετε μια καλή ιδέα για το τι είναι τα συμφραζόμενα και το escaping. Και δεν χρειάζεται να ανησυχείτε ότι είναι περίπλοκο. Το Latte το κάνει αυτό για εσάς αυτόματα.

Latte vs Naive Systems

Δείξαμε πώς να αποφεύγετε σωστά τα δεδομένα σε ένα έγγραφο HTML και πόσο κρίσιμο είναι να γνωρίζετε το πλαίσιο, δηλαδή το πού βγάζετε τα δεδομένα. Με άλλα λόγια, πώς λειτουργεί το context sensitive escaping. Αν και αυτό είναι απαραίτητη προϋπόθεση για τη λειτουργική άμυνα XSS, Το Latte είναι το μόνο σύστημα template για την PHP που το κάνει αυτό.

Πώς είναι αυτό δυνατόν όταν όλα τα συστήματα σήμερα ισχυρίζονται ότι διαθέτουν αυτόματη διαφυγή; Η αυτόματη διαφυγή χωρίς γνώση του πλαισίου είναι μια μαλακία που δημιουργεί μια ψευδή αίσθηση ασφάλειας.

Τα συστήματα δημιουργίας προτύπων όπως το Twig, το Laravel Blade και άλλα δεν βλέπουν καμία δομή HTML στο πρότυπο. Επομένως, δεν βλέπουν ούτε τα συμφραζόμενα. Σε σύγκριση με το Latte, είναι τυφλά και αφελή. Χειρίζονται μόνο τη δική τους σήμανση, όλα τα άλλα είναι μια άσχετη ροή χαρακτήρων γι' αυτά:

░░░░░░░░░░░░░░░░░{{ text }}░░░░░░░
░░░░░░░░░░░░░░░░{{ text }}░░░░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ text }}░░░░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ text }}░░░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ text }}░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ text }}░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ text }}░░░░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ text }}░░░░░░░░░
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░{{ text }}░░░░░░░░░░░
░░░░░░░░░░░░░░░░░░░{{ text }}░░░░
- in text: <span>{{ text }}</span>
- in tag: <span {{ text }} ></span>
- in attribute: <span title='{{ text }}'></span>
- in unquoted attribute: <span title={{ text }}></span>
- in attribute containing URL: <a href="{{ text }}"></a>
- in attribute containing JavaScript: <img onload="{{ text }}">
- in attribute containing CSS: <span style="{{ text }}"></span>
- in JavaScriptu: <script>var = {{ text }}</script>
- in CSS: <style>body { content: {{ text }}; }</style>
- in comment: <!-- {{ text }} -->

Τα αφελή συστήματα μετατρέπουν μηχανικά τους χαρακτήρες < > & ' " σε οντότητες HTML, που είναι ένας έγκυρος τρόπος διαφυγής στις περισσότερες χρήσεις, αλλά όχι πάντα. Έτσι, δεν μπορούν να ανιχνεύσουν ή να αποτρέψουν διάφορα κενά ασφαλείας, όπως θα δείξουμε παρακάτω.

Η Latte βλέπει το πρότυπο με τον ίδιο τρόπο που το βλέπετε κι εσείς. Κατανοεί την HTML, την XML, αναγνωρίζει τις ετικέτες, τα χαρακτηριστικά κ.λπ. Και εξαιτίας αυτού, κάνει διάκριση μεταξύ των πλαισίων και αντιμετωπίζει τα δεδομένα ανάλογα. Έτσι, προσφέρει πραγματικά αποτελεσματική προστασία από την κρίσιμη ευπάθεια Cross-site Scripting.

Ζωντανή επίδειξη

Στα αριστερά μπορείτε να δείτε το πρότυπο στο Latte, ενώ στα δεξιά είναι ο παραγόμενος κώδικας HTML. Η μεταβλητή $text εξάγεται αρκετές φορές, κάθε φορά σε ελαφρώς διαφορετικό πλαίσιο. Και ως εκ τούτου διαφυλάσσεται λίγο διαφορετικά. Μπορείτε να επεξεργαστείτε τον κώδικα του προτύπου μόνοι σας, για παράδειγμα να αλλάξετε το περιεχόμενο της μεταβλητής κ.λπ. Δοκιμάστε το:

{* TRY TO EDIT THIS TEMPLATE *}
{var $text = "Rock'n'Roll"}
- <span>{$text}</span>
- <span title='{$text}'></span>
- <span title={$text}></span>
- <img onload="{$text}">
- <script>var = {$text}</script>
- <!-- {$text} -->
- <span>Rock'n'Roll</span>
- <span title='Rock&apos;n&apos;Roll'></span>
- <span title="Rock&apos;n&apos;Roll"></span>
- <img onload="&quot;Rock&apos;n&apos;Roll&quot;">
- <script>var = "Rock'n'Roll"</script>
- <!-- Rock'n'Roll -->

Δεν είναι υπέροχο! Το Latte κάνει αυτόματα τη διαφυγή με ευαισθησία περιβάλλοντος, έτσι ώστε ο προγραμματιστής:

  • δεν χρειάζεται να σκέφτεται ή να γνωρίζει πώς να αποφεύγει δεδομένα
  • δεν μπορεί να κάνει λάθος
  • δεν μπορεί να το ξεχάσει

Αυτά δεν είναι καν όλα τα συμφραζόμενα που διακρίνει η Latte κατά την εξαγωγή και για τα οποία προσαρμόζει την επεξεργασία των δεδομένων. Θα εξετάσουμε τώρα περισσότερες ενδιαφέρουσες περιπτώσεις.

Πώς να χακάρετε τα αφελή συστήματα

Θα χρησιμοποιήσουμε μερικά πρακτικά παραδείγματα για να δείξουμε πόσο σημαντική είναι η διαφοροποίηση του πλαισίου και γιατί τα αφελή συστήματα templating δεν παρέχουν επαρκή προστασία έναντι του XSS, σε αντίθεση με το Latte. Στα παραδείγματα θα χρησιμοποιήσουμε το Twig ως εκπρόσωπο ενός αφελούς συστήματος, αλλά το ίδιο ισχύει και για άλλα συστήματα.

Ευπάθεια χαρακτηριστικών

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

<img src={{ imageFile }} alt={{ imageAlt }}>

Σημειώστε ότι δεν υπάρχουν εισαγωγικά γύρω από τις τιμές του χαρακτηριστικού. Ο κωδικοποιητής μπορεί να τα ξέχασε, κάτι που απλά συμβαίνει. Για παράδειγμα, στο React, ο κώδικας γράφεται έτσι, χωρίς εισαγωγικά, και ένας προγραμματιστής που αλλάζει γλώσσα μπορεί εύκολα να ξεχάσει τα εισαγωγικά.

Ο επιτιθέμενος εισάγει ένα έξυπνα κατασκευασμένο αλφαριθμητικό foo onload=alert('Hacked!') ως λεζάντα εικόνας. Γνωρίζουμε ήδη ότι το Twig δεν μπορεί να καταλάβει αν μια μεταβλητή εκτυπώνεται σε μια ροή κειμένου HTML, μέσα σε ένα χαρακτηριστικό, μέσα σε ένα σχόλιο HTML κ.ο.κ. Με λίγα λόγια, δεν κάνει διάκριση μεταξύ των πλαισίων. Και απλά μετατρέπει μηχανικά τους χαρακτήρες < > & ' " σε οντότητες HTML. Έτσι, ο κώδικας που θα προκύψει θα μοιάζει ως εξής:

<img src=photo0145.webp alt=foo onload=alert(&#039;Hacked!&#039;)>

Δημιουργήθηκε ένα κενό ασφαλείας!

Ένα ψεύτικο χαρακτηριστικό onload έχει γίνει μέρος της σελίδας και το πρόγραμμα περιήγησης το εκτελεί αμέσως μετά τη λήψη της εικόνας.

Ας δούμε τώρα πώς χειρίζεται το ίδιο πρότυπο η Latte:

<img src={$imageFile} alt={$imageAlt}>

Latte βλέπει το πρότυπο με τον ίδιο τρόπο που το βλέπετε εσείς. Σε αντίθεση με το Twig, καταλαβαίνει την HTML και γνωρίζει ότι μια μεταβλητή εκτυπώνεται ως τιμή χαρακτηριστικού που δεν είναι σε εισαγωγικά. Γι' αυτό και τα προσθέτει. Όταν ένας επιτιθέμενος εισάγει την ίδια λεζάντα, ο κώδικας που προκύπτει θα μοιάζει κάπως έτσι:

<img src="photo0145.webp" alt="foo onload=alert(&apos;Hacked!&apos;)">

Το latte απέτρεψε επιτυχώς το XSS.

Εκτύπωση μιας μεταβλητής σε JavaScript

Χάρη στη διαφυγή με ευαισθησία περιβάλλοντος, είναι δυνατή η χρήση μεταβλητών της PHP εγγενώς μέσα στη JavaScript.

<p onclick="alert({$movie})">{$movie}</p>

<script>var movie = {$movie};</script>

Εάν η μεταβλητή $movie αποθηκεύει το αλφαριθμητικό 'Amarcord & 8 1/2', παράγει την ακόλουθη έξοδο. Παρατηρήστε τη διαφορετική διαφυγή που χρησιμοποιείται στην HTML και τη JavaScript, καθώς και στο χαρακτηριστικό onclick:

<p onclick="alert(&quot;Amarcord &amp; 8 1\/2&quot;)">Amarcord &amp; 8 1/2</p>

<script>var movie = "Amarcord & 8 1\/2";</script>

Το Latte ελέγχει αυτόματα αν η μεταβλητή που χρησιμοποιείται στα χαρακτηριστικά src ή href περιέχει μια διεύθυνση URL στο διαδίκτυο (δηλαδή πρωτόκολλο HTTP) και αποτρέπει τη συγγραφή συνδέσμων που μπορεί να αποτελέσουν κίνδυνο για την ασφάλεια.

{var $link = 'javascript:attack()'}

<a href={$link}>click here</a>

Γράφει:

<a href="">click here</a>

Ο έλεγχος μπορεί να απενεργοποιηθεί χρησιμοποιώντας το φίλτρο nocheck.

Όρια του Latte

Το Latte δεν αποτελεί πλήρη προστασία XSS για ολόκληρη την εφαρμογή. Θα μας δυσαρεστούσε αν σταματούσατε να σκέφτεστε την ασφάλεια όταν χρησιμοποιείτε το Latte. Ο στόχος του Latte είναι να διασφαλίσει ότι ένας επιτιθέμενος δεν μπορεί να αλλάξει τη δομή μιας σελίδας, να αλλοιώσει στοιχεία ή χαρακτηριστικά HTML. Δεν ελέγχει όμως την ορθότητα του περιεχομένου των δεδομένων που εξάγονται. Ή την ορθότητα της συμπεριφοράς της JavaScript. Αυτό είναι πέρα από το πεδίο εφαρμογής του συστήματος διαμόρφωσης προτύπων. Η επαλήθευση της ορθότητας των δεδομένων, ειδικά αυτών που εισάγονται από τον χρήστη και συνεπώς δεν είναι αξιόπιστα, είναι ένα σημαντικό έργο για τον προγραμματιστή.