Сразу узкий вывод: самоуничтожение держит только одну фразу — после исчерпания числа прочтений или по истечении срока шифротекста на сервере нет, повторный запрос по тому же id исходные байты не вернёт. Оно не держит «получатель не сделал скриншот», «в чате никто третий не открывал» и «в резервной копии переписки нет полной ссылки». Проверка — два открытия плюс Network, а не чтение «Сожжена» как аудита чужого телефона.
Сначала одним предложением — ответ на запрос
Самоуничтожающаяся ссылка доказывает, что хостинг больше не держит шифротекст. Она не доказывает, что стёрли экран, буфер обмена и историю чата получателя. После первого успешного забора то же открытие показывает «Сожжена» или «Истекла». По смыслу HTTP 410 Gone целевой ресурс на источнике уже недоступен, и это состояние почти всегда постоянное. Так отвечают на вопрос «сервер ещё отдаёт?». На вопрос «у него осталась копия?» — нет.
Заметка для разработчиков, администраторов и тех, кто перед отправкой одноразового пароля, API-ключа или кода восстановления коллеге хочет развести «ссылка больше не работает» и «у него ничего не осталось». Это не инструкция к самоуничтожающейся ссылке и не повтор «как собрать URL». Унести отсюда стоит другое: какой слой сгорает, что доказывает неудачное обновление, почему скриншот лежит за этой границей и как два открытия плюс Network сверяют сторону хостинга на этом устройстве.
«Сожжена» и «у получателя не осталось копии» — разные факты
В бытовой речи три разных события склеивают в одну фразу «сообщение исчезло после прочтения». Первое: сервер больше не хранит шифротекст. Запись с этим id удалена, следующий запрос даёт только «Сожжена» или «Истекла». Второе: текущая вкладка больше не показывает открытый текст. Это даёт закрытие страницы, кнопка «Убрать с этой страницы» или скрипт, который чистит поле при уходе. Третье: на устройстве получателя нет ни одной копии — ни скриншота, ни вставки, ни пересланной полной ссылки, ни открытого текста, возвращённого в чат.
Самоуничтожение принудительно закрывает только первое. Второе оно в лучшем случае подчищает на этой вкладке. На третье у него нет силы. Страница чтения может честно написать, что не блокирует копирование и снимок экрана. Это граница, а не недоделанная функция: обычная веб-страница не умеет запретить второму телефону сфотографировать монитор и не умеет зайти в системный буфер или локальную базу Telegram после нажатия «Копировать открытый текст».
Поэтому «я обновил — уже не открывается» держит только узкий вывод: этот запрос по id шифротекст не вернул. Он не держит «смотрел только тот коллега», «он не сделал скриншот» и «эта строка больше не всплывёт в поиске по тикетам». Такие фразы требуют другого наблюдения: ушёл ли открытый текст или полный URL из этой вкладки, а не упало ли ваше второе открытие.
Какой слой сервер сжигает на самом деле
Ссылка с нулевым знанием разводит поиск и расшифровку. Форма такая: s.html?id={id}#{key}. После вопроса только идентификатор, ключ стоит только после решётки. RFC 9110 говорит: целевой URI запроса не включает fragment. Когда браузер просит у сервера документ, он отбрасывает # и всё, что дальше. По задумке сервер видит id, не видит ключ и не видит открытый текст.
При создании вкладка через Web Crypto собирает AES-256-GCM: случайный ключ 32 байта, IV 12 байт, открытый текст на этом устройстве сворачивается в шифротекст и только потом уходит POST /secrets. Наружу — шифротекст, срок жизни и число прочтений. Ключ появляется лишь в ссылке, которую вы потом собираете. Одна запись — не больше 32 КБ. Срок можно поставить 1 час, 24 часа, 7 дней или сжечь только после прочтения. Число прочтений — от 1 до 10, по умолчанию 1. Создавать и читать можно сразу. Аккаунта нет, логина «кто открыл» тоже нет.
При чтении сервер после успешной выдачи и исчерпания заданного числа прочтений удаляет этот шифротекст. Повторное открытие показывает «Сожжена» или «Истекла». Это доказывает: хостинг больше не держит эти зашифрованные байты. Это не доказывает: ключ никогда не сидел в истории чата, открытый текст никогда не появился на чужом экране, третий человек никогда не нажал «Открыть и посмотреть» по той же полной ссылке.
Ключ остаётся у того, у кого есть вся строка. Вставить в общий чат https://…/s.html?id=…#… — значит одновременно отдать и номер, и ключ. Даже если сервер уже сжёг шифротекст, это удаление не отменяет того, кто уже открыл и оставил открытый текст у себя. Если прочтения ещё не кончились, поздний клик всё ещё заберёт блок. Сжечь шифротекст — закрыть долгое хранение у хостинга. Слой «кто увидел всю строку» это не закрывает.
Что доказывает неудачное обновление — и чего не доказывает
Второе открытие, которое не сработало, — это не один статус. Разведите три подсказки. «Сожжена»: шифротекста уже нет, потому что исчерпали число прочтений или id с самого начала был пустым. «Истекла»: вышел TTL, выбранный при создании, сервер удалил запись, даже если никто не читал. «Нет ключа в фрагменте»: идентификатор ещё может жить, но это устройство расшифровать не может. Часть почтовых клиентов и некоторые мессенджеры отрезают всё после #. Тогда получатель видит «Нет ключа» — и это не то же событие, что «кто-то уже прочитал».
410 Gone значит: целевой ресурс на источнике больше недоступен, и это, скорее всего, навсегда. Страница чтения делит 410 на «Сожжена» и «Истекла»: если в ответе есть expired, это TTL; иначе считают сожжением. 404 тоже показывают как «Сожжена», потому что для получателя итог один — шифротекст больше не забрать. Обрыв сети сожжением не считается: если связь пропала уже после «Открыть и посмотреть», а при создании разрешили одно прочтение, блок могли уже забрать, хотя эта вкладка его так и не расшифровала.
Значит, «у меня после обновления не открывается» держит только это: запрос по этому id шифротекст больше не отдаёт. Он не держит: открыл именно названный коллега; он не копировал; он не сделал скриншот; превью Telegram или почтовый шлюз не потратили прочтение раньше. Без аккаунтов нет именной квитанции о прочтении. Счётчик живёт на сервере. Это не аудит устройства получателя.
Не ставьте опыт на живом пароле, API-ключе или незамаскированной строке подключения. Напишите фразу, которая существует только для этой проверки. Сверяете статус, забор шифротекста и подсказку второго открытия — а не светите рабочий секрет ещё раз.
Почему скриншот, копирование и история чата лежат за этой границей
Как только открытый текст нарисован на экране, вопрос «есть ли шифротекст на сервере?» сменяется вопросом «что произошло на том конце». Системный скриншот, запись экрана или второй телефон, наведённый на монитор, не шлют хостингу ни одного запроса. Страница чтения это не перехватит и потом вам не напишет. Это не галочка, которую «забыли сделать в продукте». Обычной веб-странице не дают выключатель «запретить человеку снимать свой экран».
Копирование стоит по ту же сторону забора. Страница может дать «Копировать открытый текст» и очистить поле при уходе. Чистится узел DOM, не системный буфер и не черновик в Telegram. На macOS и в части методов ввода ещё есть история буфера. «Удалено с этой страницы» значит только то, что эта вкладка фразу больше не показывает. Это не значит, что фраза никогда не попадала в буфер.
История чата — отдельное хранилище. Если полная ссылка мелькнула в группе, история комнаты, поиск, синхронизация на несколько устройств и поздний экспорт снова покажут ключ после решётки. Даже когда сервер уже сжёг шифротекст, URL остаётся доказательством, что ссылка когда-то работала, и этого хватает, чтобы человек, который не знает про исчерпанный счётчик, кликал снова и решил: «ссылка сломалась». HTTP-слой при этом может оставаться чистым — в Referer fragment по спецификации не кладут, — но против того, кто откроет переписку, эта защита уже не работает.
Тикеты, почта и история браузера режутся тем же ножом. Фрагмент #, который побывал в адресной строке, обычно оседает в локальной истории; браузер с включённой синхронизацией может унести ту же запись на другие устройства. Закрыть вкладку — не значит очистить историю. Самоуничтожение сокращает, сколько хостинг хранит блок, и сколько раз один и тот же шифротекст можно забрать. Это не управление цифровыми правами и не отчёт для экспертизы.
Почему запрос статуса не тратит прочтение
Если бы уже первая загрузка посадочной забирала шифротекст, превью в Telegram, почтовый шлюз безопасности или корпоративный сканер могли бы потратить единственное прочтение раньше получателя. Тогда он увидел бы «Сожжена», хотя ключ превью-хосту не отдавали. Сгорает счётчик, не секретность fragment. В предыдущей заметке разобрано, почему решётка по умолчанию не входит в HTTP. Здесь смотрим только счётчик: запрос превью и настоящий забор шифротекста должны быть разными шагами, иначе «Сожжена» не доказывает даже фразу «получатель это видел».
Страница чтения FastPwd эти шаги разводит. Открытие страницы делает только /secrets/{id}/status: шифротекст ещё на месте? Сам блок не забирают. После нажатия «Открыть и посмотреть» вкладка делает GET /secrets/{id} и расшифровывает локально ключом после решётки. Если ключа после # нет, страница шифротекст не запросит — чтобы не сжечь оставшиеся прочтения. Ни создание, ни чтение не требуют аккаунта.
Боты превью обычно тянут посадочную и кнопку за вас не жмут. Это снижает шанс «превью равно сожжению». Это не доказывает, что любой сканер остановится там же. В Network сначала должен появиться status, потом — забор шифротекста; загрузка без клика не должна показать успешный забор блока. Счётчик по-прежнему серверный. В fragment он не входит.
| Что вы видите | Какой вывод это держит | Какой вывод это не держит |
|---|---|---|
| Второе открытие показывает «Сожжена» | Сейчас по этому id шифротекст не отдают | Получатель не сделал скриншот и не копировал |
| Подсказка «Истекла» | Вышел TTL, сервер удалил запись | Кто-то обязательно успешно прочитал |
| Подсказка «Нет ключа» | В адресе нет ключа после # |
Шифротекст уже точно забрали |
| Страницу открыли, кнопку не нажимали | Запрос status не должен тратить прочтение | Любой бот превью шифротекст не заберёт |
| В Network у POST только шифротекст | В этом создании исходную фразу не отправили как рабочее поле | После вставки полной ссылки в чат её видите только вы |
| «Удалено с этой страницы» | Текущая вкладка фразу больше не показывает | В буфере и на скриншоте её тоже нет |
Сверьте на месте: два открытия, status, Network
Слоган — не доказательство. Напишите одноразовую канарейку, например canary-fp-20260905-burn-vs-shot, живой пароль не повторяйте. Число прочтений оставьте по умолчанию — 1, срок — 24 часа.
- На странице создания вставьте канарейку и получите ссылку. Откройте Network, включите Preserve log. Вставьте в поиск отдельно канарейку и ключ после решётки: в теле
POST /secretsдолжны быть шифротекст, срок и число прочтений — не исходная фраза и не ключ. - Откройте страницу чтения полной ссылкой и пока не нажимайте «Открыть и посмотреть». В Network должен появиться
/secrets/{id}/status, успешногоGET /secrets/{id}, который забирает блок, быть не должно. Страница должна остаться в состоянии «Ждём подтверждения». - Нажмите «Открыть и посмотреть». Вот здесь шифротекст забирают по id и на этом устройстве раскрывают AES-256-GCM. После успеха страница напишет: сервер уже удалил этот шифротекст — или, если вы поставили число прочтений больше 1, удалит только после заданного лимита.
- Обновите страницу чтения или откройте ту же ссылку в чистом контексте браузера. При одном прочтении должна появиться «Сожжена»; в Network забор шифротекста должен вернуть 410 или ответ, который страница читает как сожжение. Канарейка больше не должна всплыть открытым текстом ни в одном теле запроса.
Эти четыре шага доказывают одну вещь: между двумя открытиями, которые вы контролируете, шифротекст на сервере из «ещё есть» стал «уже нет». Они не доказывают: если это был настоящий пароль коллеге, он не сделал скриншот. Привычку «оставит ли он копию» можно записать только в свою памятку передачи: не снимать экран, не возвращать открытый текст в общий чат, сразу сменить пароль после использования. Надпись «Сожжена» чужой телефон за вас не проверит.
Полную ссылку и сам секрет не ведите одним каналом. Файл .lock можно положить на диск или в почту, пароль — отдельной самоуничтожающейся ссылкой. Полный URL этой ссылки не пишите в комментарий к той же папке на диске. Ключ и ящик в одном сообщении — и сожжённый шифротекст уже не спасёт тех, кто увидел всю строку.
Три случая, когда «Сожжена» читают слишком широко
Первый: принять истечение за чтение. Поставили срок 1 час, коллега открыл на следующий день и увидел «Истекла». Сервер шифротекст тоже удалил, но причина — TTL, а не исчерпанный счётчик. Непрочитанное с истекшим сроком не вернуть. Это всё равно не равно «уже открывали».
Второй: принять отсутствие фрагмента за сожжение. Почта и часть клиентов режут всё после #. Получатель открывает s.html?id=… без ключа. Пока ключа нет, страница чтения шифротекст не забирает. Ваша полная ссылка чуть позже может ещё работать. Тогда нужно попросить прислать строку вместе с решёткой, а не сразу решать, что «кто-то прочитал раньше».
Третий: принять очистку вкладки за глобальную зачистку. Страница может очистить поле при уходе и через history.replaceState убрать fragment из адресной строки. Это влияет на показ в этой вкладке и на то, останется ли ключ при следующем обновлении. Системный скриншот, история буфера, резервная копия чата и синхронизированная история браузера в этот сброс не входят.
Частые вопросы
Если получатель обновил страницу и увидел «Сожжена», значит ли это, что у него ничего не осталось?
Нет. Это значит только то, что шифротекста на сервере уже нет и повторный запрос по тому же идентификатору исходные байты не вернёт. Скриншот, копирование, запись экрана, резервная копия чата и пересылка полной ссылки третьему человеку через это удаление не проходят. «Сожжена» — не доказательство, что устройство получателя чистое.
Может ли превью ссылки в мессенджере сжечь секрет раньше получателя?
Превью обычно открывает только посадочную. Страница чтения сначала спрашивает, на месте ли ещё шифротекст, и сам блок не забирает; «Открыть и посмотреть» — это уже запрос по id. Большинство ботов превью кнопку за вас не нажимают, но нельзя считать, что любой сканер остановится на лендинге. Счётчик прочтений живёт на сервере. Сверка такая: открыли и не нажимали — в Network не должно быть успешного забора шифротекста.
Доказывает ли самоуничтожающаяся ссылка, кто именно её открыл?
Нет. Создавать и читать можно без аккаунта, сервер не помечает читателя логином. Сверить можно одно: после этого забора шифротекста идентификатор ещё жив или уже нет. Из «Сожжена» не следует, кто нажал, и это нельзя писать как именную квитанцию о прочтении.
Нужна ли регистрация, чтобы создать или прочитать ссылку? Уходит ли открытый текст на сервер?
Регистрация не нужна. Текущая вкладка шифрует открытый текст алгоритмом AES-256-GCM и отправляет только шифротекст. Ключ стоит в фрагменте ссылки после #. Ищите в Network канарейку: в теле должен быть шифротекст, а не исходная фраза и не ключ после решётки. Текст длиннее 32 КБ или целый файл лучше отдать в шифрование файлов на этом устройстве — самоуничтожающуюся ссылку диском не заменяйте.
Прогоните ту же канарейку на инструменте, который сразу готов
Если нужна страница, где эта граница уже проговорена, откройте самоуничтожающуюся ссылку FastPwd. Открыли — и можно пользоваться, регистрация не нужна. Вставьте канарейку выше, число прочтений оставьте 1 и пройдите два открытия из четвёртого раздела. Смотрите Network параллельно: должны появиться POST шифротекста при создании, status на странице чтения, забор после клика и ответ сожжения на втором открытии. Исходной фразы и ключа после решётки как рабочих полей быть не должно.
Живой пароль коллеге отправляйте только по этой дороге. Случайный пароль можно сначала собрать в генераторе паролей на этом устройстве: длина 6–128 символов, по умолчанию 16; короче 8 — пометка, что защита слабее. Генерация ничего не загружает. Договор, скан паспорта или материал длиннее 32 КБ лучше закрыть в шифровании файлов тем же AES-256-GCM в .lock / .enc, один файл — не больше 5 ГБ. Пароль к файлу всё равно ведите отдельной самоуничтожающейся ссылкой, не пишите его в комментарий к папке на диске.
Перед следующей отправкой оставьте себе три строки. Первое: «Сожжена» доказывает, что шифротекста на сервере нет, а не то, что получатель не сделал скриншот. Второе: одно открытие посадочной прочтение тратить не должно; шифротекст забирает только «Открыть и посмотреть». Третье: после вставки полной ссылки в чат ключ после решётки уже открыт всем, кто видит сообщение. В собственную памятку стоит писать только то наблюдение, которое можно повторить.
Что ещё почитать
Почему кусок после решётки по умолчанию не входит в HTTP и какой слой падает, если переслать ссылку целиком, — в Почему после решётки в URL можно класть ключ и когда эта защита ломается. Почему фразу «локальное шифрование, ничего не загружается» нельзя принимать на слово и как искать канарейку в Network — в Как проверить, что локальное шифрование в браузере не отправило открытый текст. Если перед отправкой нужно закрыть номера документов в теле тикета, рядом лежит Перед тем как вставить тикеты и логи в ИИ, сверьте, какие поля покинут это устройство.