Για ομάδες InfoSec και αξιολογητές εφαρμογών
Ασφάλεια στο Peel
Με λίγα λόγια: το περιεχόμενο του πίνακα κρυπτογραφείται στον browser με ένα κλειδί που βρίσκεται στο fragment του συνδέσμου, οπότε οι servers μας αποθηκεύουν και μεταφέρουν κρυπτογραφημένο κείμενο που δεν μπορούν να διαβάσουν. Παρακάτω εξηγούμε ακριβώς πώς, και πού είναι τα όρια.
Σύνοψη
- Το κείμενο των καρτών, τα ονόματα, οι τίτλοι πινάκων, οι ψήφοι και τα αυτοκόλλητα κρυπτογραφούνται με AES-256-GCM με ένα κλειδί πίνακα που δημιουργείται στον browser. Το κλειδί ταξιδεύει στο fragment του URL (
#k=) και δεν αποστέλλεται ποτέ σε server. - Οι ενέργειες του συντονιστή, η κεφαλίδα του πίνακα και τα στιγμιότυπα υπογράφονται με το κλειδί Ed25519 του συντονιστή. Το αναγνωριστικό του πίνακα παράγεται από αυτό το κλειδί, οπότε οι clients εντοπίζουν κάθε αντικατάσταση κλειδιού.
- Οι κρυφές κάρτες είναι σφραγισμένες για τον συντονιστή (X25519 sealed box) μέχρι την αποκάλυψη, και δεσμεύονται με δεσμεύσεις με salt, ώστε το αποκαλυμμένο κείμενο να μην μπορεί να αλλαχτεί.
- Ανώνυμα από προεπιλογή: οι λειτουργίες δεν φέρουν αναγνωριστικό συντάκτη· οι ψήφοι και οι αντιδράσεις χρησιμοποιούν τυχαίο αναγνωριστικό ανά πίνακα.
- Οι συμμετέχοντες δεν ταυτοποιούνται ποτέ. Χωρίς analytics SDK, χωρίς διαφημίσεις, χωρίς scripts τρίτων, εκτός από το Paddle.js στη σελίδα πληρωμής.
- Μόνο Cloudflare. Οι πίνακες χωρίς κάτοχο διαγράφονται 60 μέρες μετά την τελευταία επίσκεψη.
Πώς ρέουν τα δεδομένα
Το fragment ενός URL (ό,τι ακολουθεί το #) το χειρίζεται ο browser και δεν αποτελεί μέρος του αιτήματος HTTP. Εκεί βάζει το Peel το κλειδί του πίνακα.
Μοντέλο απειλών
Σχεδιάζουμε ώστε ένας πλήρως παραβιασμένος ή περίεργος server, ακόμα και εμείς, να μαθαίνει όσο το δυνατόν λιγότερα για όσα λέει μια ομάδα.
Τι προστατεύουμε
- Κείμενο καρτών, επιλογές GIF και, στην επώνυμη λειτουργία, το όνομα του συντάκτη.
- Ονόματα και avatar συμμετεχόντων, το όνομα του πίνακα και οι τίτλοι προσαρμοσμένων προτύπων.
- Ποιος ψήφισε ή αντέδρασε σε τι, και ποιος έγραψε ποια κάρτα.
- Η ακεραιότητα του retro: βήματα, αποκαλύψεις και αποφάσεις του συντονιστή δεν πλαστογραφούνται.
Αντίπαλοι που λαμβάνουμε υπόψη
- Οι δικοί μας servers, ένας κακόβουλος εσωτερικός ή κάποιος που παραβιάζει την αποθήκευσή μας: παίρνουν κρυπτογραφημένο κείμενο και μεταδεδομένα.
- Ένας επιτιθέμενος στο δίκτυο: TLS παντού· το κλειδί δεν περνάει ποτέ από το δίκτυο.
- Ένας server που αντικαθιστά κλειδιά: το αναγνωριστικό του πίνακα παράγεται από το δημόσιο κλειδί του συντονιστή και οι clients επαληθεύουν την υπογεγραμμένη κεφαλίδα.
- Ένας συμμετέχων που θέλει να κρυφοκοιτάξει ή να πλαστογραφήσει: οι κρυφές κάρτες είναι σφραγισμένες για τον συντονιστή· οι λειτουργίες του συντονιστή απαιτούν την υπογραφή του· οι επεξεργασίες καρτών απαιτούν το κλειδί της κάρτας.
- Ένας συντονιστής που αναδημοσιεύει για συντάκτη εκτός σύνδεσης: οι δεσμεύσεις τον εμποδίζουν να αλλάξει το κείμενο.
Εκτός εμβέλειας, με ειλικρίνεια
- Όποιος έχει τον σύνδεσμο συμμετέχοντα μπορεί να διαβάσει τον πίνακα. Ο σύνδεσμος είναι ο έλεγχος πρόσβασης. Μοιράσου τον με την ίδια προσοχή που θα έδειχνες για τον ίδιο τον πίνακα.
- Μια παραβιασμένη συσκευή, μια κακόβουλη επέκταση browser ή κάποιος που κοιτάζει πάνω από τον ώμο σου.
- Ανάλυση κίνησης: ο server βλέπει χρονισμό, μεγέθη και πλήθη (δες τον χάρτη δεδομένων).
- Άρνηση υπηρεσίας από τον server: μπορεί να απορρίψει ή να καθυστερήσει μηνύματα, όχι όμως να τα διαβάσει ή να τα πλαστογραφήσει.
Κρυπτογραφία
Όλες οι κρυπτογραφικές βασικές λειτουργίες προέρχονται από το WebCrypto API του browser. Καμία δική μας κρυπτογραφία, καμία κρυπτογραφική βιβλιοθήκη τρίτων.
| Κλειδί | Αλγόριθμος | Χρήση |
|---|---|---|
| K_board | AES-256-GCM, τυχαίο IV 96 bit | Κρυπτογραφεί κάθε λειτουργία, στιγμιότυπο και ενημέρωση παρουσίας. Τα πρόσθετα δεδομένα (additional data) δεσμεύουν το αναγνωριστικό του πίνακα, τον τύπο και το αναγνωριστικό της λειτουργίας, ώστε το κρυπτογραφημένο κείμενο να μην μπορεί να αναπαραχθεί σε άλλον πίνακα ή θέση. Βρίσκεται μόνο στο fragment του συνδέσμου #k=. |
| K_owner | Ed25519 | Η εξουσία του συντονιστή. Υπογράφει τις λειτουργίες του συντονιστή (βήμα, χρονόμετρο, προσκήνιο, πρότυπο, ρυθμίσεις, άνοιγμα ψηφοφορίας, απόκρυψη κάρτας), την κεφαλίδα του πίνακα και τα στιγμιότυπα. Ένας αυστηρά αύξων μετρητής αποτρέπει την επανάληψη (replay). Μόνο στον σύνδεσμο συντονιστή (&o=). |
| Αναγνωριστικό πίνακα | SHA-256, πρώτα 80 bit, base32 | Παράγεται από το δημόσιο κλειδί του συντονιστή, οπότε το ίδιο το αναγνωριστικό αποδεικνύει ποιο κλειδί κατέχει τον πίνακα. Οι clients απορρίπτουν μια κεφαλίδα της οποίας το κλειδί δεν αντιστοιχεί, μέσω hash, στο αναγνωριστικό. |
| K_fac | X25519 sealed box: εφήμερο X25519 + HKDF-SHA256 + AES-256-GCM | Οι κρυφές κάρτες σφραγίζονται με το δημόσιο κλειδί του συντονιστή όσο γράφουν οι συμμετέχοντες. Μόνο ο σύνδεσμος συντονιστή (&f=) μπορεί να τις ανοίξει. |
| Κλειδιά καρτών | Ed25519, ένα κλειδί ανά κάρτα | Τα έχει μόνο ο συντάκτης. Οι επεξεργασίες και η αποκάλυψη υπογράφονται με αυτά: αυθεντικότητα χωρίς ταυτότητα. |
| Δεσμεύσεις (commitments) | HMAC-SHA256 με τυχαίο salt 128 bit | Μια κρυφή κάρτα δημοσιεύει μια δέσμευση για το περιεχόμενό της. Στην αποκάλυψη δημοσιεύονται το περιεχόμενο και το salt και κάθε client τα ελέγχει, ώστε κανείς να μην μπορεί να αλλάξει το κείμενο. |
| Παρουσία | AES-256-GCM με το K_board | Τα ονόματα, τα avatar και οι ενδείξεις πληκτρολόγησης κρυπτογραφούνται όπως όλα τα υπόλοιπα. |
| Πακέτο κλειδιών | HKDF-SHA256 από passkey PRF ή κωδικό ανάκτησης, AES-256-GCM | Οι συνδεδεμένοι συντονιστές μπορούν να συγχρονίζουν τα κλειδιά των πινάκων μεταξύ συσκευών. Το πακέτο κρυπτογραφείται στη συσκευή· ο server αποθηκεύει μόνο κρυπτογραφημένο κείμενο και τυλιγμένα (wrapped) κλειδιά. |
Τα μηνύματα υπογραφής έχουν διαχωρισμό πεδίου (domain separation, για παράδειγμα peel/sig/v1, peel/header/v1, peel/snap/v1), ώστε μια υπογραφή για έναν σκοπό να μην μπορεί να χρησιμοποιηθεί για άλλον.
Ανωνυμία
- Οι λειτουργίες δεν φέρουν αναγνωριστικό συντάκτη. Ο server δεν μπορεί να συνδέσει μια κάρτα με ένα πρόσωπο, και από προεπιλογή ούτε ο συντονιστής.
- Οι ψήφοι και οι αντιδράσεις αντιστοιχίζονται σε ένα τυχαίο αναγνωριστικό ανά πίνακα, που δεν συνδέεται με κάποιο όνομα.
- Οι ενδείξεις πληκτρολόγησης δείχνουν ότι κάποιος γράφει, ποτέ τι γράφει.
- Η επώνυμη λειτουργία είναι ρητή ρύθμιση του πίνακα· τότε το όνομα του συντάκτη ταξιδεύει μέσα στην κρυπτογραφημένη κάρτα.
- Οι συμμετέχοντες δεν συνδέονται ποτέ, άρα δεν υπάρχει λογαριασμός για συσχέτιση.
Χάρτης δεδομένων
Ό,τι κρατάμε, πού βρίσκεται, ποιος μπορεί να το διαβάσει και για πόσο μένει.
| Δεδομένα | Πού | Ποιος τα διαβάζει | Διατήρηση |
|---|---|---|---|
| Κάρτες, ψήφοι, αντιδράσεις, αυτοκόλλητα, ενέργειες, όνομα πίνακα, τίτλοι προσαρμοσμένων προτύπων | Αποθήκευση Durable Object, κρυπτογραφημένα | Όσοι έχουν τον σύνδεσμο του πίνακα | Μέχρι να διαγραφεί ο πίνακας |
| Φάκελος λειτουργίας: τύπος, σειρά και ώρα στον server, μέγεθος, μετρητής συντονιστή | Αποθήκευση Durable Object | Peel | Μέχρι να διαγραφεί ο πίνακας |
| Ονόματα συμμετεχόντων, avatar, πληκτρολόγηση | Μεταφέρονται κρυπτογραφημένα· κρατιούνται στη μνήμη όσο διαρκεί η σύνδεση | Όσοι έχουν τον σύνδεσμο του πίνακα | Όσο διαρκεί η σύνδεση |
| Κατάσταση πίνακα: βήμα, πλήθος συμμετεχόντων και καρτών, αναγνωριστικό προτύπου του καταλόγου, ένδειξη κλειδώματος, ώρες δημιουργίας και λήξης | Durable Object, D1· μηνύματα Slack/Teams αν είναι εγκατεστημένα | Peel· το κανάλι σου στο Slack/Teams | Όσο ζει ο πίνακας |
| Λογαριασμός συντονιστή: αναγνωριστικό παρόχου, όνομα, email αν κοινοποιηθεί, συνδεδεμένοι πάροχοι, ημερομηνία δημιουργίας, συνεδρία | D1 | Peel | Μέχρι να διαγράψεις τον λογαριασμό |
| Πακέτο κλειδιών και τυλιγμένα κλειδιά | D1, κρυπτογραφημένα | Μόνο εσύ (passkey ή κωδικός ανάκτησης) | Μέχρι να διαγράψεις τον λογαριασμό |
| Πλάνο, κατάσταση συνδρομής, αναγνωριστικά πελάτη και συνδρομής στην Paddle | D1· Paddle | Peel, Paddle | Όσο απαιτεί η φορολογική νομοθεσία |
| Αναγνωριστικά χώρου εργασίας, καναλιού και μηνυμάτων Slack/Teams· token του bot (κρυπτογραφημένο με AES-GCM) | D1 | Peel | Μέχρι την απεγκατάσταση |
| Διεύθυνση IP | Edge του Cloudflare, προσωρινά (παράδοση, όρια ρυθμού) | Cloudflare, ο περιοριστής ρυθμού του Peel | Δεν αποθηκεύεται στις βάσεις δεδομένων μας |
| Ημερήσιοι μετρητές (πίνακες που δημιουργήθηκαν, βήματα που ολοκληρώθηκαν) | D1 | Peel | Μόνο συγκεντρωτικά, χωρίς αναγνωριστικά |
Τι μπορεί και τι δεν μπορεί να κάνει ο server μας
Μπορεί
- Να βλέπει τύπους, μεγέθη και χρονισμό των λειτουργιών, το βήμα, το πλήθος συμμετεχόντων και καρτών, το αναγνωριστικό προτύπου του καταλόγου και την ένδειξη κλειδώματος.
- Να απορρίπτει, να καθυστερεί ή να αρνείται την παράδοση λειτουργιών (άρνηση υπηρεσίας).
- Να βλέπει διευθύνσεις IP στο edge του δικτύου.
- Να μετράει πίνακες και βήματα που ολοκληρώθηκαν, συγκεντρωτικά.
- Να διαγράφει έναν πίνακα (λήξη, αναφορές κατάχρησης).
Δεν μπορεί
- Να διαβάσει κείμενο καρτών, ονόματα, τίτλους πινάκων, τίτλους προσαρμοσμένων προτύπων, ψήφους ή αυτοκόλλητα.
- Να διαβάσει κρυφές κάρτες πριν από την αποκάλυψη (ούτε καν μετά).
- Να πλαστογραφήσει ενέργειες του συντονιστή: χρειάζονται την υπογραφή του συντονιστή.
- Να αντικαταστήσει τα κλειδιά με δικά του: το αναγνωριστικό του πίνακα θα το πρόδιδε.
- Να αλλάξει το αποκαλυμμένο κείμενο μιας κάρτας: οι δεσμεύσεις και οι υπογραφές των καρτών θα το πρόδιδαν.
- Να ξέρει ποιος έγραψε ποια κάρτα.
Όπως σε κάθε web εφαρμογή, εμπιστεύεσαι τον κώδικα που σερβίρουμε. Κρατάμε αυτή την επιφάνεια μικρή: αυστηρή Content Security Policy, script-src περιορισμένο στο δικό μας origin, κανένα script τρίτων, και το πρωτόκολλο είναι διαθέσιμο για έλεγχο κατόπιν αιτήματος.
Slack και Microsoft Teams
- Τα μηνύματα μεταφέρουν τον σύνδεσμο του πίνακα και μεταδεδομένα (τίτλο, βήμα, πλήθη). Κείμενο καρτών αποστέλλεται μόνο όταν ο συντονιστής δημοσιεύσει σύνοψη και την επιβεβαιώσει.
- Η κάρτα συμμετοχής περιέχει τον σύνδεσμο συμμετέχοντα, ο οποίος περιλαμβάνει το κλειδί. Όποιος διαβάζει το κανάλι μπορεί να μπει, όπως ακριβώς αν επικολλούσες εκεί έναν σύνδεσμο.
- Οι προεπισκοπήσεις συνδέσμων (unfurls) δείχνουν μόνο βήμα και πλήθη, ποτέ περιεχόμενο.
- Δικαιώματα (scopes) στο Slack:
commands,chat:write,links:read,links:write·users:readμόνο όταν μια ομάδα ενεργοποιεί τις αναφορές. - Τα tokens των bot αποθηκεύονται κρυπτογραφημένα (AES-GCM, με κλειδί που φυλάσσεται ως μυστικό του Worker). Οι υπογραφές αιτημάτων του Slack και τα tokens του Bot Framework επαληθεύονται σε κάθε αίτημα.
- Η απεγκατάσταση της εφαρμογής σταματά κάθε δημοσίευση και διαγράφει τα tokens της.
Web και υποδομή
- Μόνο Cloudflare: Pages, Workers, Durable Objects, D1, R2 και KV στον λογαριασμό της 1801 Labs. Κανένας άλλος server.
- TLS παντού, HSTS και αυστηρή Content Security Policy.
- Χωρίς analytics SDK, χωρίς διαφημίσεις, χωρίς scripts τρίτων. Η μόνη εξαίρεση είναι το Paddle.js, που φορτώνεται μόνο στη σελίδα πληρωμής.
- Ένα cookie, μόνο για συνδεδεμένους συντονιστές:
peel_session, httpOnly, Secure, SameSite=Lax. - Η αναζήτηση GIF και τα πολυμέσα περνούν από το API μας, οπότε οι διευθύνσεις IP των συμμετεχόντων δεν φτάνουν ποτέ στο GIPHY.
- Οι γραμματοσειρές και τα αρχεία φιλοξενούνται από εμάς. Χωρίς γραμματοσειρές από CDN, χωρίς tracking pixels.
- Όρια ρυθμού ανά IP και ανά πίνακα· αναφορές κατάχρησης και κλείδωμα από τον συντονιστή.
Λογαριασμοί και διατήρηση δεδομένων
- Οι συμμετέχοντες δεν ταυτοποιούνται ποτέ. Οι συντονιστές συνδέονται με Google (ή με Entra ID μέσω Teams) μόνο για να κρατούν πίνακες ή να χρησιμοποιούν επί πληρωμή λειτουργίες.
- Ένας λογαριασμός αποθηκεύει ένα αναγνωριστικό, το όνομα και το email από τον πάροχο, και ένα κρυπτογραφημένο πακέτο κλειδιών που ξεκλειδώνει με passkey (WebAuthn PRF) ή κωδικό ανάκτησης. Η σύνδεση δίνει ιδιοκτησία, όχι πρόσβαση στο περιεχόμενο.
- Η διεκδίκηση ενός πίνακα αποδεικνύει την ιδιοκτησία με υπογραφή συντονιστή. Τα κλειδιά του πίνακα δεν αποστέλλονται ποτέ.
- Οι πίνακες χωρίς λογαριασμό διαγράφονται 60 μέρες μετά την τελευταία επίσκεψη· κάθε επίσκεψη μηδενίζει το χρονόμετρο. Η αποθήκευση διαγράφεται μέσω alarms των Durable Objects.
- Η διαγραφή του λογαριασμού σου διαγράφει τις συνεδρίες, το πακέτο κλειδιών και τη βιβλιοθήκη σου, και επαναφέρει στους πίνακές σου τη λήξη των 60 ημερών.
Υπεύθυνη γνωστοποίηση
Βρήκες κάτι; Πες το πρώτα σε εμάς και θα το λύσουμε μαζί. Επιβεβαιώνουμε τη λήψη των αναφορών μέσα σε τρεις εργάσιμες μέρες.
- Δώσε μας εύλογο χρόνο (στόχος μας είναι οι 90 μέρες) για να το διορθώσουμε πριν το δημοσιοποιήσεις.
- Κάνε δοκιμές με τους δικούς σου πίνακες και λογαριασμούς. Μην αποκτάς πρόσβαση σε δεδομένα άλλων και μην υποβαθμίζεις την υπηρεσία.
- Δεν θα κινηθούμε νομικά για έρευνα καλής πίστης που ακολουθεί αυτούς τους κανόνες.
- Επικοινωνία σε μορφή αναγνώσιμη από μηχανές:
/.well-known/security.txt.
Οι πελάτες του πλάνου Εταιρεία λαμβάνουν πακέτο αξιολόγησης ασφάλειας (απαντήσεις σε ερωτηματολόγια, υποεκτελούντες την επεξεργασία, ροές δεδομένων). DPA · Απόρρητο