Вы отправили коллеге одноразовую ссылку с паролем в Telegram. Через десять секунд он открывает её: «Записка уже прочитана и удалена». В чате только двое. Кто успел раньше?
Иногда — программа, которая готовила превью. Это не доказательство взлома или чтения пароля посторонним. В неудачно устроенном сервисе достаточно запросить страницу, чтобы уничтожить секретную записку. Получается обидно: секрет никто не увидел, а передавать его придётся заново. Аналогичный сценарий возможен в Slack, Discord и WhatsApp; многое зависит от реализации сервиса и клиента.
Как боты мессенджеров генерируют превью ссылок
Карточка с заголовком и картинкой не появляется сама. Когда ссылка попадает в сообщение, а иногда ещё на этапе его подготовки, мессенджер может запустить автоматическую загрузку. Обычно это HTTP GET, после которого краулер ищет в HTML теги og:title, og:description и og:image. Изображение может загружаться отдельным запросом.
В логах встречаются подписи вроде TelegramBot, Slackbot-LinkExpanding, WhatsApp и Discordbot. Это примеры, не исчерпывающий список. Slack прямо описывает сбор метатегов своим роботом; время запуска, кеширование и поведение других клиентов могут отличаться.
Важная деталь: фрагмент после # не входит в HTTP-запрос. Для ссылки https://createsecurelink.com/n/Ab3dE5fG7h#key сервер получит путь без #key. Обычный HTML-краулер от этого запроса не узнаёт ключ и не расшифровывает записку.
Но представьте наивный обработчик GET /note/id: найти шифртекст, удалить его из базы, вернуть страницу. Он не спрашивает, кто пришёл за заголовком. Запрос уже состоялся — запись стёрта. Конфиденциальность могла сохраниться, доступность нет. Это разные свойства безопасности.
При расследовании полезнее смотреть момент запроса к API чтения, а не только загрузку HTML. И не проверять свежую одноразовую ссылку лишним открытием: сама диагностика может потратить единственный просмотр.
Почему User-Agent и чёрные списки IP не гарантируют защиту
Первое желание — запретить TelegramBot. Для одного известного краулера фильтр может помочь, но строить на нём всю защиту рискованно.
Загрузка не обязательно приходит с сервера мессенджера. В мобильных сценариях, включая iMessage, WhatsApp и встроенные WebView, нельзя рассчитывать на единственный заголовок или диапазон адресов для всех версий. Превью либо предварительная загрузка могут использовать браузерный движок устройства. Обычный User-Agent не доказывает, что человек уже решил прочитать секрет.
Проверкой занимается не только мессенджер. Microsoft Defender Safe Links проверяет адреса при обработке почты и переходах; Mimecast также описывает сканирование ссылок. Некоторые системы используют браузерные или изолированные среды. Нельзя утверждать, что они всегда представляются Chrome, но нельзя и считать строку Chrome гарантией ручного открытия.
IP-списки тоже не отвечают на вопрос о намерении посетителя: один адрес может обслуживать множество пользователей. Такие фильтры полезны против злоупотреблений, но не заменяют правильный момент расходования просмотра.
Архитектура Secure Link: страница отдельно, чтение отдельно
У Secure Link загрузка страницы /n/[id] ведёт на локализованную оболочку. Её HTML и общие метатеги не содержат секрета; сама загрузка не расходует просмотр в Redis. Отдельный metadata-preview также не уменьшает счётчик.
Чтение выполняется другим запросом: GET /api/notes/[id]. Именно он получает шифртекст и расходует просмотр. Для заметки с единственным открытием сервер удаляет запись, а браузер расшифровывает полученные данные локально. Ключ из # не требуется передавать API.
Здесь необходимо честное уточнение. В текущей версии нет обязательной кнопки «Показать секрет». При корректном ключе клиент запрашивает данные автоматически. В парольном режиме шифртекст тоже запрашивается до ввода пароля, поэтому пароль защищает расшифровку, но не гарантирует сохранение просмотра при автоматическом запуске клиента.
Обычный HTML-бот не выполняет этот сценарий. Сканер с JavaScript и полной ссылкой — может. Более строгая двухшаговая схема откладывала бы запрос чтения до отдельного действия получателя. Такое подтверждение уменьшает риск случайного открытия, хотя само по себе не доказывает, что посетитель человек. Называть его уже реализованной функцией Secure Link было бы неверно.
Кто вызывает запрос и что происходит
Под «наивным сервисом» ниже имеется в виду реализация, которая расходует просмотр на GET страницы, а не любой конкурент.
| Кто пришёл | Наивный сервис | Secure Link сейчас |
|---|---|---|
| Бот превью Telegram / Slack / Discord | Записка может сгореть при отправке | HTML-превью не расходует просмотр |
| Почтовый сканер, например Safe Links | Записка может исчезнуть до получателя | HTML-проверка безопасна; запуск JS может вызвать чтение |
| Prefetch / Prerender браузера | Есть риск потери просмотра | HTML-prefetch не читает секрет; prerender с JS несёт риск |
| Реальный получатель | Прочитает, если запись ещё существует | API расходует просмотр; расшифровка в браузере, удаление по лимиту |
Prefetch и prerender здесь не синонимы: предварительная загрузка HTML не равна полноценному запуску страницы. Поэтому одного слова «предзагрузка» недостаточно для обещания безопасности.
Как отправлять секреты в мессенджерах
- Выбирайте сервис с раздельной выдачей оболочки и содержимого. Если требуется обязательное подтверждение, проверьте наличие именно отложенного чтения, а не только парольной формы.
- При необходимости отключайте карточку превью перед отправкой. Это снижает вероятность лишней загрузки, но не отменяет корпоративные проверки.
- Используйте Split-link: ссылку отправьте в Telegram, ключ — другим каналом. Два соседних сообщения в одном чате такого разделения не дают.
- Добавляйте сильный пароль. Burn-on-Failure расходует оставшиеся просмотры при неверных попытках в штатном клиенте, но не заменяет надёжную парольную фразу.
- Если ссылка уже сгорела, создайте новую. Не вставляйте секрет в чат в обход защиты только ради того, чтобы быстрее закончить передачу.