За екипи по информационна сигурност и рецензенти на приложения

Сигурността в Peel

Накратко: съдържанието на таблото се криптира в браузъра с ключ, който живее във фрагмента на линка, така че сървърите ни съхраняват и препращат шифрован текст, който не могат да прочетат. Ето как точно става това и къде са границите.

Резюме

  • Текстът на картите, имената, заглавията на таблата, гласовете и стикерите се криптират с AES-256-GCM с ключ на таблото, генериран в браузъра. Ключът пътува във фрагмента на URL адреса (#k=) и никога не се изпраща до сървър.
  • Действията на фасилитатора, заглавната част на таблото и моментните снимки се подписват с Ed25519 ключа на фасилитатора. Идентификаторът на таблото се извлича от този ключ, така че клиентите засичат подмяна на ключа.
  • Скритите карти са запечатани за фасилитатора (X25519 sealed box) до разкриването и обвързани с ангажименти със сол, така че разкритият текст не може да бъде подменен.
  • Анонимно по подразбиране: операциите не носят идентификатор на автора; гласовете и реакциите използват случаен идентификатор за всяко табло.
  • Участниците никога не се удостоверяват. Без SDK за анализи, без реклами, без скриптове на трети страни освен Paddle.js на страницата за плащане.
  • Само Cloudflare. Неприсвоените табла се изтриват 60 дни след последното посещение.

Как текат данните

Фрагментът на URL адреса (всичко след #) се обработва от браузъра и не е част от HTTP заявката. Peel слага ключа на таблото там.

Поток на данните: ключът се прочита локално от линка; през мрежата минават само шифрован текст и минимални метаданни.

Модел на заплахите

Проектираме така, че напълно компрометиран или любопитен сървър, включително нашият, да научава възможно най-малко за това какво казва един екип.

Какво защитаваме

  • Текстът на картите, избраните GIF-ове и, в режим с имена, името на автора.
  • Имената и аватарите на участниците, името на таблото и заглавията на собствени шаблони.
  • Кой за какво е гласувал или реагирал и кой коя карта е написал.
  • Целостта на ретрото: стъпките, разкриванията и решенията на фасилитатора не могат да бъдат фалшифицирани.

Противници, които отчитаме

  • Собствените ни сървъри, злонамерен служител или някой, който пробие хранилището ни: получават шифрован текст и метаданни.
  • Нападател в мрежата: TLS навсякъде; ключът никога не минава през мрежата.
  • Сървър, който подменя ключове: идентификаторът на таблото се извлича от публичния ключ на фасилитатора, а клиентите проверяват подписаната заглавна част.
  • Участник, който иска да надникне или да фалшифицира: скритите карти са запечатани за фасилитатора; операциите на фасилитатора изискват неговия подпис; редакциите на карта изискват ключа на картата.
  • Фасилитатор, който публикува повторно вместо офлайн автор: ангажиментите не му позволяват да промени текста.

Извън обхвата, честно казано

  • Всеки, който има линка за участници, може да чете таблото. Линкът е контролът на достъпа. Пази го и го споделяй така, както споделяш самото табло.
  • Компрометирано устройство, злонамерено разширение на браузъра или някой, който наднича през рамото ти.
  • Анализ на трафика: сървърът вижда времето, размерите и бройките (виж картата на данните).
  • Отказ на услуга от страна на сървъра: може да изпуска или забавя съобщения, но не и да ги чете или фалшифицира.

Криптография

Всички примитиви идват от WebCrypto API на браузъра. Без собствена криптография, без криптографски библиотеки на трети страни.

КлючАлгоритъмИзползва се за
K_boardAES-256-GCM, 96-битов случаен IVКриптира всяка операция, моментна снимка и обновяване на присъствието. Допълнителните данни свързват идентификатора на таблото, типа и идентификатора на операцията, така че шифрованият текст не може да бъде повторно използван в друго табло или позиция. Живее само във фрагмента на линка #k=.
K_ownerEd25519Правомощията на фасилитатора. Подписва операциите на фасилитатора (стъпка, таймер, прожектор, шаблон, настройки, отваряне на гласуването, скриване на карта), заглавната част на таблото и моментните снимки. Строго нарастващ брояч блокира повторното възпроизвеждане. Само в линка на фасилитатора (&o=).
Идентификатор на таблотоSHA-256, първите 80 бита, base32Извлича се от публичния ключ на фасилитатора, така че самият идентификатор доказва кой ключ притежава таблото. Клиентите отхвърлят заглавна част, чийто ключ не съответства на хеша на идентификатора.
K_facX25519 sealed box: ефимерен X25519 + HKDF-SHA256 + AES-256-GCMДокато хората пишат, скритите карти се запечатват с публичния ключ на фасилитатора. Само линкът на фасилитатора (&f=) може да ги отвори.
Ключове на картитеEd25519, по един ключ за картаДържи ги само авторът. С тях се подписват редакциите и разкриването: автентичност без идентичност.
Ангажименти (commitments)HMAC-SHA256 със 128-битова случайна солСкритата карта публикува ангажимент към съдържанието си. При разкриването съдържанието и солта се публикуват и всеки клиент ги проверява, така че никой не може да подмени текста.
ПрисъствиеAES-256-GCM с K_boardИмената, аватарите и индикаторите за писане се криптират като всичко останало.
Архив с ключовеHKDF-SHA256 от passkey PRF или код за възстановяване, AES-256-GCMВлезлите фасилитатори могат да синхронизират ключовете на таблата между устройствата. Архивът се криптира на устройството; сървърът съхранява само шифрован текст и обвити ключове.

Подписваните съобщения са с разделени домейни (например peel/sig/v1, peel/header/v1, peel/snap/v1), така че подпис за една цел не може да се използва повторно за друга.

Скрити карти и разкриване

  1. Докато авторът пише, браузърът му запечатва картата с X25519 ключа на фасилитатора и публикува ангажимент със сол. Откритият текст остава на устройството на автора.
  2. Другите участници виждат скрита карта: не могат да я декриптират, както не може и сървърът.
  3. Браузърът на фасилитатора може да отваря запечатаните карти (прегледът „👁 само ти“).
  4. При разкриването всеки автор публикува картата отново, криптирана с K_board и подписана с ключа на картата, заедно със солта.
  5. Ако автор е офлайн, фасилитаторът я публикува вместо него. Всеки клиент проверява ангажимента, така че текстът трябва да съвпада с написаното от автора.

Тъй като фасилитаторът технически може да преглежда картите предварително, всяко табло показва на всички етикет „фасилитаторът може да преглежда“, докато картите са скрити. Това не е настройка, която може да се скрие.

Анонимност

  • Операциите не носят идентификатор на автора. Сървърът не може да свърже карта с човек, а по подразбиране не може и фасилитаторът.
  • Гласовете и реакциите се водят под случаен идентификатор за всяко табло, който не е свързан с име.
  • Индикаторите за писане показват, че някой пише, но никога какво.
  • Режимът с имена е изрична настройка на таблото; тогава името на автора пътува вътре в криптираната карта.
  • Участниците никога не влизат в профил, така че няма профил, с който да бъдат свързани.

Карта на данните

Всичко, което съхраняваме, къде се намира, кой може да го чете и колко време остава.

ДанниКъдеКой може да четеСрок
Карти, гласове, реакции, стикери, действия, име на таблото, заглавия на собствени шаблониХранилище на Durable Object, като шифрован текстХората, които имат линка към таблотоДокато таблото не бъде изтрито
Плик на операцията: тип, пореден номер и време от сървъра, размер, брояч на фасилитатораХранилище на Durable ObjectPeelДокато таблото не бъде изтрито
Имена на участниците, аватари, индикатор за писанеПрепраща се като шифрован текст; държи се в паметта, докато има връзкаХората, които имат линка към таблотоДокато има връзка
Статус на таблото: стъпка, брой участници и карти, идентификатор на шаблона от каталога, флаг за заключване, време на създаване и изтичанеDurable Object, D1; съобщения в Slack/Teams, ако е инсталираноPeel; твоят канал в Slack/TeamsДокато таблото съществува
Профил на фасилитатор: идентификатор от доставчика, име, имейл (ако е споделен), свързани доставчици, дата на създаване, сесияD1PeelДокато не изтриеш профила
Архив с ключове и обвити ключовеD1, като шифрован текстСамо ти (passkey или код за възстановяване)Докато не изтриеш профила
План, статус на абонамента, идентификатори на клиента и абонамента в PaddleD1; PaddlePeel, PaddleСпоред изискванията на данъчното законодателство
Идентификатори на работното пространство, канала и съобщенията в Slack/Teams; токен на бота (криптиран с AES-GCM)D1PeelДо деинсталиране
IP адресМрежата на Cloudflare, временно (доставка, ограничения на заявките)Cloudflare, ограничителят на заявки на PeelНе се съхранява в нашите бази данни
Дневни броячи (създадени табла, достигнати стъпки)D1PeelСамо обобщено, без идентификатори

Какво може и какво не може сървърът ни

Може

  • Да вижда типовете операции, размерите, времето, стъпката, броя участници и карти, идентификатора на шаблона от каталога и флага за заключване.
  • Да изпусне, забави или откаже да достави операции (отказ на услуга).
  • Да вижда IP адресите в периферията на мрежата.
  • Да брои таблата и достигнатите стъпки, обобщено.
  • Да изтрие табло (изтичане на срока, сигнали за злоупотреба).

Не може

  • Да чете текста на картите, имената, заглавията на таблата, заглавията на собствени шаблони, гласовете или стикерите.
  • Да чете скритите карти преди разкриването (нито след него).
  • Да фалшифицира действия на фасилитатора: за тях е нужен подписът на фасилитатора.
  • Да подмени ключовете със свои: идентификаторът на таблото ще го издаде.
  • Да промени разкрития текст на карта: ангажиментите и подписите на картите ще го издадат.
  • Да разбере кой коя карта е написал.

Както при всяко уеб приложение, ти се доверяваш на кода, който сервираме. Държим тази повърхност малка: строга Content Security Policy, script-src ограничен до нашия собствен произход, без скриптове на трети страни, а протоколът е отворен за преглед при поискване.

Slack и Microsoft Teams

  • Съобщенията носят линка към таблото и метаданни (заглавие, стъпка, бройки). Текстът на картите се изпраща само когато фасилитаторът публикува обобщение и го потвърди.
  • Картата за влизане съдържа линка за участници, който включва ключа. Всеки, който чете този канал, може да влезе – все едно линкът е поставен там.
  • Прегледите на линкове показват само стъпката и бройките, никога съдържание.
  • Права в Slack: commands, chat:write, links:read, links:write; users:read само когато екипът включи споменаванията.
  • Токените на бота се съхраняват криптирани (AES-GCM, ключът се пази като Worker secret). Подписите на заявките от Slack и токените на Bot Framework се проверяват при всяка заявка.
  • Деинсталирането на приложението спира всички публикации и изтрива токените му.

Уеб и инфраструктура

  • Само Cloudflare: Pages, Workers, Durable Objects, D1, R2 и KV в акаунта на 1801 Labs. Никакви други сървъри.
  • TLS навсякъде, HSTS и строга Content Security Policy.
  • Без SDK за анализи, без реклами, без скриптове на трети страни. Единственото изключение е Paddle.js, който се зарежда само на страницата за плащане.
  • Една бисквитка, само за влезли фасилитатори: peel_session, httpOnly, Secure, SameSite=Lax.
  • Търсенето на GIF-ове и медията минават през нашия API, така че IP адресите на участниците никога не стигат до GIPHY.
  • Шрифтовете и ресурсите се хостват при нас. Без шрифтове от CDN, без проследяващи пиксели.
  • Ограничения на заявките по IP и по табло; сигнали за злоупотреба и заключване от фасилитатора.

Профили и съхранение

  • Участниците никога не се удостоверяват. Фасилитаторите влизат с Google (или с Entra ID през Teams) само за да пазят табла или да използват платени функции.
  • Профилът съхранява идентификатор, името и имейла от доставчика и криптиран архив с ключове, който се отключва с passkey (WebAuthn PRF) или с код за възстановяване. Влизането дава собственост, а не достъп до съдържанието.
  • При присвояване на табло собствеността се доказва с подпис на фасилитатора. Ключовете на таблото никога не се изпращат.
  • Таблата без профил се изтриват 60 дни след последното посещение; всяко посещение нулира брояча. Хранилището се изтрива от аларми на Durable Object.
  • Изтриването на профила изтрива сесиите, архива с ключове и библиотеката ти и връща 60-дневния срок на таблата ти.

Отговорно разкриване на уязвимости

Откри нещо? Първо ни кажи и ще работим заедно. Потвърждаваме получаването на доклади в рамките на три работни дни.

[email protected]

  • Моля, дай ни разумно време (целим 90 дни) да поправим проблема, преди да го оповестиш.
  • Тествай със собствени табла и профили. Не достъпвай чужди данни и не влошавай услугата.
  • Няма да предприемаме правни действия срещу добросъвестни проучвания, които спазват тези правила.
  • Машинночетим контакт: /.well-known/security.txt.

Клиентите с план „Компания“ получават пакет за преглед на сигурността (отговори на въпросници, подизпълнители по обработката, потоци на данни). DPA · Поверителност