Ασφάλεια

    Σαρωτές συνδέσμων και μυστικά μίας χρήσης

    Ο σύνδεσμος μίας χρήσης που διαγράφεται με απλό GET χάνεται στην προεπισκόπηση του Slack ή του email. Μεταδεδομένα στο GET, διαγραφή μόνο με ρητή εμφάνιση.

    W. Miller · Ενημερώθηκε · Σχετικά με το LinkPilot

    Ένας σύνδεσμος μίας χρήσης που διαγράφεται οριστικά με ένα απλό GET χάνεται τη στιγμή που το Slack, το Teams ή ένα σύστημα ασφάλειας email τον ανοίγει για να φτιάξει προεπισκόπηση. Η λύση είναι να επιστρέφετε μόνο μεταδεδομένα στο GET και να διαγράφετε το μυστικό μόνο με ρητή εμφάνιση μέσω POST, με μια φράση πρόσβασης που στέλνεται από δεύτερο κανάλι ως δίχτυ ασφαλείας. Αυτό το άρθρο εξηγεί ποια συστήματα ανοίγουν συνδέσμους χωρίς να ρωτήσουν και πώς σχεδιάζετε ώστε να μην επηρεάζεστε από κανένα τους.

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

    Η συνηθισμένη αποτυχία

    Τα περισσότερα προγράμματα συνομιλίας και email προσπαθούν να δείξουν προεπισκόπηση όταν βλέπουν ένα URL. Η ροή είναι η εξής:

    1. Ο χρήστης επικολλά τον μυστικό σύνδεσμο στο Slack.
    2. Ο μηχανισμός προεπισκόπησης του Slack ανοίγει το URL (στέλνει GET, και το Slack τεκμηριώνει τη συμπεριφορά στην ενότητα link unfurling).
    3. Ο κώδικας που χειρίζεται την εμφάνιση αντιμετωπίζει το αίτημα σαν προβολή από άνθρωπο, διαγράφει οριστικά το μυστικό και επιστρέφει το περιεχόμενο.
    4. Το Slack λαμβάνει το περιεχόμενο του μυστικού που μόλις διαγράφηκε (ή μια γενική σελίδα) και το εμφανίζει.
    5. Ο άνθρωπος πατά τον σύνδεσμο, βλέπει «έχει ήδη προβληθεί» και ζητά από τον αποστολέα έναν καινούργιο.

    Ο μηχανισμός προεπισκόπησης δεν είχε κακή πρόθεση. Ο κώδικάς σας μπέρδεψε το «κάποιος άνοιξε το URL» με το «ο παραλήπτης διάβασε το μυστικό». Είναι διαφορετικά γεγονότα, και όλο το πρόβλημα του σχεδιασμού είναι να μένουν χωριστά.

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

    Μηχανισμοί προεπισκόπησης σε εφαρμογές συνομιλίας, συστήματα ασφάλειας email, προστασία τερματικών, εταιρικοί proxy και επεκτάσεις προεπισκόπησης, και συνήθως περισσότεροι από ένας. Η φράση «το Slack φτιάχνει προεπισκοπήσεις» υποτιμά το πρόβλημα. Ένα URL που επικολλάται σε ένα σύγχρονο εργασιακό περιβάλλον το ανοίγουν συνήθως αρκετά συστήματα πριν το πατήσει οποιοσδήποτε άνθρωπος:

    Ποιος το ανοίγειΠότεΑναγνωρίζεται;
    Μηχανισμοί προεπισκόπησης σε συνομιλίες (Slack, Teams, iMessage, WhatsApp, LinkedIn)Τη στιγμή που στέλνεται το μήνυμαΣυνήθως ναι, με ξεχωριστά user agent όπως το Slackbot-LinkExpanding
    Συστήματα ασφάλειας email (Mimecast, Proofpoint, Microsoft Defender)Κατά την παράδοση, και συχνά ξανά τη στιγμή του κλικΣυχνά όχι, πολλά εμφανίζονται με user agent πραγματικού προγράμματος περιήγησης
    Προστασία τερματικών / antivirusΌταν το URL φτάσει στον υπολογιστή του παραλήπτηΣπάνια
    Εταιρικοί web proxyΤη στιγμή του κλικ, πριν προωθηθεί το αίτημα του χρήστηΣπάνια
    Επεκτάσεις προεπισκόπησης συνδέσμωνΌταν περνά ο δείκτης από πάνω ή όταν φορτώνει η σελίδαΌχι, χρησιμοποιούν την ίδια τη συνεδρία του προγράμματος περιήγησης του χρήστη

    Η συμπεριφορά των παρόχων σε αυτόν τον πίνακα αλλάζει συνεχώς. Δείτε τους συγκεκριμένους ισχυρισμούς για τα συστήματα ασφάλειας ως «όπως δημοσιεύτηκαν τον Ιούλιο του 2026, ελέγξτε την τρέχουσα τεκμηρίωση». Το κοινό σημείο όμως δεν αλλάζει: όλα αυτά τα συστήματα στέλνουν ένα απλό GET, επειδή αυτός είναι ο μόνος ασφαλής και καθολικός τρόπος να κοιτάξει κανείς ένα URL που δεν ελέγχει.

    Επιστρέψτε μεταδεδομένα στο GET και διαγράψτε οριστικά μόνο με ρητό POST. Η σημασιολογία του HTTP το προβλέπει ήδη: το RFC 9110, ενότητα 9.2.1 ορίζει το GET ως ασφαλές και idempotent, δηλαδή ένα αίτημα που μπορεί να στείλει ελεύθερα οποιοσδήποτε, επειδή δεν υποτίθεται ότι αλλάζει τίποτα. Το POST είναι το ρήμα της ενέργειας. Χειριστείτε λοιπόν την εμφάνιση ως ενέργεια POST πίσω από ένα ορατό κουμπί:

    GET  /s/abc123   →  HTML page: "Click to reveal this secret"
    POST /s/abc123   →  burns the secret, returns the payload
    

    Τώρα το GET του Slack επιστρέφει μια ουδέτερη σελίδα μεταδεδομένων. Το μυστικό χάνεται μόνο όταν ο άνθρωπος πατήσει το κουμπί. Κάθε σαρωτής που σέβεται τη σημασιολογία του HTTP δεν αγγίζει ποτέ το περιεχόμενο. Αυτό ισχύει σχεδόν για όλους, γιατί αν έστελναν POST με παρενέργειες σε τυχαία URL θα χαλούσαν τον μισό ιστό.

    Ένα παράδειγμα βήμα προς βήμα

    Ακολουθήστε έναν σύνδεσμο από την αρχή ως το τέλος. Δημιουργείτε ένα μυστικό με διαγραφή μετά την ανάγνωση και φράση πρόσβασης, και επικολλάτε το URL σε ένα προσωπικό μήνυμα στο Slack και σε ένα email.

    1. Ο μηχανισμός προεπισκόπησης του Slack στέλνει GET /s/abc123. Απάντηση: μια μικρή σελίδα μεταδεδομένων, με κατάσταση «active» (ενεργός) και την ένδειξη ότι απαιτείται φράση πρόσβασης. Καμία προβολή δεν καταγράφεται. Το μυστικό υπάρχει ακόμη.
    2. Το σύστημα ασφάλειας email του παραλήπτη ξαναγράφει το URL μέσα στο email και το ανοίγει τη στιγμή της παράδοσης για έλεγχο φήμης. Ίδιο GET, ίδια μεταδεδομένα. Το μυστικό υπάρχει ακόμη.
    3. Ο παραλήπτης πατά τον σύνδεσμο στο email. Ο σαρωτής του συστήματος, τη στιγμή του κλικ, ανοίγει το URL άλλη μία φορά (GET) και μετά ανακατευθύνει το πρόγραμμα περιήγησης στον προορισμό.
    4. Το πρόγραμμα περιήγησης φορτώνει τη σελίδα εμφάνισης με ένα ακόμη GET. Η σελίδα δείχνει ένα κουμπί εμφάνισης και ένα πεδίο για τη φράση πρόσβασης. Ακόμη καμία προβολή δεν καταγράφεται.
    5. Ο παραλήπτης πληκτρολογεί τη φράση πρόσβασης και πατά το κουμπί εμφάνισης. Το πρόγραμμα περιήγησης στέλνει POST /s/abc123. Η προβολή καταγράφεται, το περιεχόμενο επιστρέφεται και το μυστικό διαγράφεται οριστικά.
    6. Όποιος ανοίξει το URL μετά παίρνει μια ρητή απάντηση «έχει ήδη προβληθεί και καταστραφεί» αντί για το περιεχόμενο.

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

    Πολλαπλά επίπεδα άμυνας

    Ο διαχωρισμός GET / POST

    Καλύπτει κάθε μηχανισμό προεπισκόπησης και σαρωτή που ακολουθεί τους κανόνες, δηλαδή τη συντριπτική πλειονότητα της αυτόματης κίνησης. Αυτό είναι το θεμέλιο. Όλα τα παρακάτω είναι πρόσθετα επίπεδα.

    Φράση πρόσβασης

    Καλύπτει ό,τι δεν καλύπτει ο διαχωρισμός: sandbox που εκτελούν JavaScript και αλληλεπιδρούν με τη σελίδα, αλλά και κλικ από άνθρωπο κατά λάθος και email που προωθήθηκαν. Ένα sandbox ανάλυσης μπορεί να πατήσει ένα κουμπί εμφάνισης. Δεν μπορεί να δώσει μια φράση πρόσβασης που ταξίδεψε από άλλο κανάλι. Στείλτε τον σύνδεσμο με email και τη φράση πρόσβασης με προσωπικό μήνυμα στο Slack ή με SMS.

    Φιλτράρισμα bot με βάση το user agent

    Απορρίψτε τα γνωστά bot προεπισκόπησης (Slackbot, LinkedInBot, Twitterbot) πριν φτάσουν σε οποιονδήποτε κώδικα εμφάνισης. Αξίζει ως επιπλέον προφύλαξη, αλλά δεν αρκεί ποτέ μόνο του: οι σαρωτές ασφαλείας εμφανίζονται συστηματικά με user agent πραγματικού προγράμματος περιήγησης, ακριβώς για να μην μπορούν οι κακόβουλες σελίδες να κρυφτούν από την ανάλυση.

    Σύντομη λήξη

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

    Cache-Control: no-store

    Ορίστε το σε κάθε απάντηση εμφάνισης, ώστε κανένας ενδιάμεσος (εταιρικός proxy, CDN, cache του προγράμματος περιήγησης) να μην κρατά αντίγραφο του περιεχομένου μετά τη μία νόμιμη ανάγνωση.

    Ειδικά για τα συστήματα ασφάλειας email

    Τα εταιρικά συστήματα ασφάλειας email αξίζουν δική τους ενότητα, επειδή ανοίγουν τον σύνδεσμο δύο φορές. Τα προϊόντα αυτής της κατηγορίας (το Microsoft Defender Safe Links είναι το τεκμηριωμένο παράδειγμα) ξαναγράφουν κάθε URL στα εισερχόμενα μηνύματα ώστε να περνά από το δικό τους domain σάρωσης. Το URL ανοίγεται συνήθως μία φορά κατά την παράδοση για έλεγχο φήμης, και ξανά τη στιγμή του κλικ, πριν ο άνθρωπος ανακατευθυνθεί στον πραγματικό προορισμό.

    Αν οποιοδήποτε από τα δύο αιτήματα διέγραφε το μυστικό, ο παραλήπτης θα έβλεπε πάντα έναν νεκρό σύνδεσμο. Οι χρήστες το βλέπουν σαν τυχαία βλάβη, ενώ είναι απολύτως προβλέψιμο. Ο διαχωρισμός GET/POST απορροφά και τα δύο αιτήματα χωρίς κόστος, αφού και τα δύο είναι απλά GET. Η ανακατεύθυνση τη στιγμή του κλικ φέρνει μετά τον άνθρωπο στη σελίδα εμφάνισης, όπου γίνεται το POST.

    Ειδικές περιπτώσεις που εξακολουθούν να προκαλούν προβλήματα

    • Sandbox που εκτελούν JavaScript. Ορισμένα περιβάλλοντα ανάλυσης φορτώνουν τη σελίδα και αλληλεπιδρούν με αυτήν. Ένα POST πίσω από ένα κουμπί χωρίς φράση πρόσβασης θα μπορούσε, θεωρητικά, να το πατήσει ένα επιθετικό sandbox. Η φράση πρόσβασης είναι το δίχτυ ασφαλείας.
    • Σύνδεσμος και φράση πρόσβασης στο ίδιο κανάλι. Αν ταξιδεύουν και τα δύο στο ίδιο email, όλες οι άμυνες παραπάνω καταλήγουν στο «ας ελπίσουμε ότι κανείς δεν θα διαβάσει αυτό το email». Να χωρίζετε πάντα τα κανάλια.
    • Προώθηση. Κάθε προώθηση σε μια νέα συνομιλία ή ένα νέο σύστημα email προκαλεί νέο γύρο προεπισκοπήσεων. Με τον διαχωρισμό δεν κάνει ζημιά, όμως κάθε βήμα προσθέτει άλλα αρχεία καταγραφής που κρατούν το URL, κάτι που συνηγορεί υπέρ της σύντομης λήξης.
    • Ταυτόχρονες εμφανίσεις. Αν δύο άνθρωποι πατήσουν εμφάνιση ταυτόχρονα, η ανάγνωση και η διαγραφή πρέπει να γίνονται σε ένα ενιαίο, αδιαίρετο βήμα: ακριβώς ένα αίτημα κερδίζει και το άλλο παίρνει «έχει ήδη προβληθεί». Μια υλοποίηση που δεν το εξασφαλίζει μπορεί να δώσει το περιεχόμενο δύο φορές.

    Δοκιμάστε το δικό σας εργαλείο

    Πριν εμπιστευτείτε πραγματικά διαπιστευτήρια σε οποιαδήποτε υπηρεσία κοινοποίησης μυστικών, κάντε αυτόν τον έλεγχο δύο λεπτών:

    1. Δημιουργήστε ένα δοκιμαστικό μυστικό με ενεργή τη διαγραφή μετά την ανάγνωση.
    2. Ανοίξτε το από ένα τερματικό, κάνοντας ακριβώς ό,τι κάνει ένας μηχανισμός προεπισκόπησης: curl -s -o /dev/null -w "%{http_code}" "<url>"
    3. Ανοίξτε τον σύνδεσμο σε ένα πρόγραμμα περιήγησης. Αν δείτε «έχει ήδη προβληθεί», το εργαλείο διαγράφει το μυστικό με το GET και δεν είναι ασφαλές να το επικολλάτε σε συνομιλίες ή email.
    4. Αν το μυστικό άντεξε, εμφανίστε το κανονικά στο πρόγραμμα περιήγησης και τρέξτε ξανά το curl. Τώρα πρέπει να πάρετε μια ρητή απάντηση ότι το μυστικό δεν υπάρχει πια ή έχει διαγραφεί, όχι το περιεχόμενο.

    Πώς το υλοποιεί το LinkPilot

    Για την ιστορία, αυτός είναι ο σχεδιασμός που χρησιμοποιούν οι μυστικοί σύνδεσμοι του LinkPilot: ένα GET στο endpoint εμφάνισης επιστρέφει μόνο μεταδεδομένα (την κατάσταση και αν απαιτείται φράση πρόσβασης). Μια προβολή καταγράφεται μόνο με ρητή εμφάνιση μέσω POST. Οι φράσεις πρόσβασης γίνονται hash με SHA-256 στο πρόγραμμα περιήγησης (client-side), με όριο πέντε προσπαθειών ανά IP ανά λεπτό για κάθε μυστικό. Κάθε απάντηση εμφάνισης φέρει Cache-Control: no-store, τα μυστικά που έχουν διαγραφεί ή λήξει επιστρέφουν HTTP 410 και το αποθηκευμένο περιεχόμενο αντικαθίσταται, και το ιστορικό ενεργειών καταγράφει κάθε γεγονός με τη διεύθυνση IP σε μορφή hash, με salt που αλλάζει καθημερινά. Η ακατέργαστη διεύθυνση IP δεν αποθηκεύεται ποτέ. Όλες οι λεπτομέρειες βρίσκονται στη σελίδα αρχιτεκτονική ασφάλειας.

    Δοκιμάστε το δωρεάν, χωρίς εγγραφή

    Αυτοκαταστρεφόμενο μήνυμα

    Στείλτε ένα σημείωμα που εξαφανίζεται αφού διαβαστεί μία φορά.

    Άνοιγμα εργαλείου

    Τα όρια αυτού του σχεδιασμού

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

    Πηγές

    Εργαλεία για αυτό το άρθρο

    Συχνές ερωτήσεις

    Το LinkPilot στέλνει έναν μυστικό σύνδεσμο που διαγράφεται μόλις ανοιχτεί.

    Κρυπτογραφείται στο πρόγραμμα περιήγησής σας, εμφανίζεται μία φορά και μετά καταστρέφεται. Χωρίς λογαριασμό.

    Δημιουργία μυστικού συνδέσμου

    Διαβάστε επίσης

    Ασφάλεια

    Πώς στέλνετε κλειδιά API με ασφάλεια

    Μην επικολλάτε κλειδιά API σε chat ή email. Στείλτε σύνδεσμο κρυπτογραφημένο στον browser σας που διαγράφεται στο πρώτο άνοιγμα και αλλάξτε όσα επικολλήσατε.

    Ασφάλεια

    Πώς λειτουργούν οι μυστικοί σύνδεσμοι μίας χρήσης

    Ο μυστικός σύνδεσμος μίας χρήσης ανοίγει μία φορά: κρυπτογραφείται στον browser, ο διακομιστής κρατά μόνο κρυπτογράφημα, η πρώτη εμφάνιση το διαγράφει.

    Ασφάλεια

    Σύνδεσμοι με λήξη: καταστροφή μυστικού, όχι ανακατεύθυνση

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