>_безопасность · шифрование · sec.teqh.org
Как передать пароль и не оставить его в переписке навсегда
Зачем я сделал sec.teqh.org: секрет шифруется прямо в браузере, сервер хранит только шифротекст, а запись удаляется сама по сроку или после нужного числа открытий.
Доступ к серверу, токен API, пароль от админки. Почти всегда их отправляют в Telegram, Slack или почту. Сообщение доходит за секунду и остаётся там на годы: в истории чата, на всех устройствах собеседника, в бэкапах и в поиске по переписке. Для таких случаев я сделал sec.teqh.org.
Что не так с паролем в мессенджере
Дело не в том, что мессенджер ненадёжный. Секрету нужно прожить пять минут, а живёт он вечно. Через год кто-то получит доступ к аккаунту получателя, к его ноутбуку или к экспорту чата и вместе со всем остальным получит ваш пароль. Удалить сообщение у себя мало: копия остаётся у второй стороны.
Нужна передача, после которой секрет исчезает сам и которую не может прочитать никто по дороге, включая сервис, через который она идёт.
Как пользоваться
- Открываете sec.teqh.org и вставляете текст: пароль, токен, ключ, кусок конфига. Любые данные до 1 000 000 байт.
- Придумываете пароль шифрования. Это не пароль от сервиса, а отдельная фраза, которую будет знать только получатель.
- При желании задаёте лимит открытий и срок жизни. По умолчанию открывать можно сколько угодно, а запись живёт сутки. Срок выбирается от 2 минут до 8 дней.
- Нажимаете
Encrypt. Сервис показывает хеш секрета, а через 20 секунд страница сама переходит на ссылку видаsec.teqh.org/s/<хеш>. - Ссылку отправляете одним каналом, пароль другим. Например, ссылку в Slack, а пароль голосом на созвоне.
- Получатель открывает ссылку, вводит пароль, нажимает
Decryptи видит текст.
Интерфейс на английском, но главное в нём два поля: текст и пароль.
Что происходит внутри
Главная идея: сервер не может прочитать то, что хранит. Это не обещание из политики конфиденциальности, а следствие того, как устроено шифрование.
- 01Браузер отправителявыводит ключ из пароля и шифрует текст
- 02Сетьпередаёт только шифротекст, salt и iv
- 03Серверхранит шифротекст, ключа у него нет
- 04Браузер получателявосстанавливает ключ из пароля и расшифровывает
- Ключ выводится из пароля через
PBKDF2-SHA256с 600 000 итераций. Прямо во вкладке, до того как что-либо уходит в сеть. - Текст шифруется
AES-256-GCM. Для каждого секрета генерируются свежие случайные salt (16 байт) и iv (12 байт). - На сервер уходят только шифротекст, salt, iv, параметры KDF и настройки срока и лимита. Пароль и исходный текст из вкладки не выходят.
- Хеш пароля сервер тоже не хранит. Пароль проверяет сам шифр: при неверном пароле не сходится проверка целостности GCM, и расшифровка не происходит. Любой проверочный хеш на сервере только ослабил бы схему.
Отсюда простое следствие: если утечёт база, в ней будут только шифротексты. Расшифровать их без паролей нечем.
Почему ссылка и пароль идут разными каналами
Ссылки достаточно, чтобы скачать шифротекст. Пароля достаточно, чтобы его расшифровать. Поодиночке ни то, ни другое секрет не открывает. Кто перехватил один канал, получил только половину.
Из этого же следует, что вся защита держится на пароле. Тот, у кого есть ссылка, может подбирать пароль у себя, без сервера. 600 000 итераций PBKDF2 делают каждую попытку дорогой, но не делают подбор невозможным. Поэтому пароль нужен длинный: фраза из нескольких случайных слов лучше короткого слова с цифрой. Интерфейс показывает, насколько пароль стойкий.
Секрет удаляется сам
У каждой записи есть срок жизни и, если вы его задали, лимит открытий. Когда срок истёк или прошло последнее разрешённое открытие, запись удаляется насовсем. Доступ закрывается ровно в момент дедлайна. Физическая очистка базы может немного отставать, но открыть просроченную запись уже нельзя.
Неверный пароль открытие не тратит. Просмотр страницы и скачивание шифротекста тоже. Открытие засчитывается только после успешной расшифровки: вместе с текстом браузер расшифровывает случайный одноразовый токен и отправляет его на сервер. Сервер хранит только SHA-256 от этого токена и по нему понимает, что секрет действительно открыли.
Мелочи, которые важны
- Браузер не предложит сохранить пароль. Поле пароля сделано так, чтобы браузер не принял его за форму входа: пароль от чужого секрета в менеджере паролей никому не нужен.
- Превью в мессенджере ничего не открывает. Страница секрета не содержит шифротекста. Браузер скачивает его только после ввода пароля и нажатия
Decrypt. Мессенджер, который строит превью ссылки, ничего не читает и не тратит открытия. - В записи секрета нет IP-адреса, User-Agent и другой телеметрии. Только шифротекст, параметры шифрования, даты и счётчик открытий.
- Строгие заголовки. Страницы отдаются с
no-storeи жёсткой Content Security Policy: скрипты только с самого сайта, без встроенного JavaScript. - Расшифрованный текст живёт только во вкладке. После перезагрузки страница снова попросит пароль.
Честно об ограничениях
- Пароль нельзя восстановить. Его нет на сервере, поэтому потерянный пароль означает потерянные данные.
- Лимит открытий управляет записью на сервере, но не отзывает то, что уже скачано или скопировано. Если получатель скопировал текст, дальше он у него.
- Изменённый клиент может скачать шифротекст и расшифровать его без сервера, не засчитав открытие. Лимит защищает от случайных и повторных открытий, а не от того, у кого уже есть и ссылка, и пароль.
- Если ответ сервера потеряется после того, как открытие засчитано, попытка может потратиться, а текст не показаться.
- Код шифрования приходит с сервера, как у любого веб-приложения. Вы доверяете тому, что страница отдаёт честный JavaScript. Это общее ограничение шифрования в браузере.
Когда это пригодится
- Отдать подрядчику доступ к серверу, CMS или рекламному кабинету.
- Передать коллеге ключ API или токен бота.
- Отправить клиенту логин и пароль от сервиса, который вы для него настроили.
- Переслать кусок конфигурации с секретами, не оставляя его в общем чате.
Попробуйте: sec.teqh.org. Если нужно встроить похожую передачу секретов в ваш продукт или процессы, напишите мне.