Приватность
Что сервер знает о вас
Содержимое переписки, звонков и вложений шифруется на телефоне — серверу оно недоступно, у него нет ключей. Но чтобы доставить сообщение, сервер обрабатывает метаданные: кому, когда, какого размера. Часть этих метаданных он сейчас может прочитать. Ниже — что именно и почему.
Это описание кода, а не юридический документ. Мы писали его, читая свой собственный код, а не переписывая чужую политику. Юрист его не смотрел. Там, где реализация отстаёт от обещаний, здесь написано «не включено», а не «включено».
Обновлено 3 сентября 2026 · оператор — тот, кто держит relay.signets.social
Коротко
Пять строк вместо десяти страниц
- Переписку, файлы и звонки сервер не читает: они зашифрованы между устройствами.
- Ни номера телефона, ни почты при регистрации нет — этих полей просто не существует в базе.
- Уведомления идут по своему постоянному соединению. Сервисы Google в доставке не участвуют.
- Аналитики, рекламы и трекеров нет ни одного. Продавать нам нечего и некому.
- Но сервер сейчас может определить, кто кому пишет. Разбор ниже, честно и подробно.
Что закрыто шифрованием
Здесь сервер видит только шифротекст
Сообщения и всё, что к ним прицеплено
Текст, фото, видео, голосовые, файлы, стикеры, реакции, правки и удаления. Всё шифруется протоколом Signal — X3DH и двойной храповик, с пост-квантовым гибридом X25519 + Kyber-1024, когда обе стороны на свежей сборке. Ключи создаются на телефоне и с него не уходят.
Звук и картинка звонка
WebRTC с DTLS-SRTP между устройствами. Когда сеть позволяет — напрямую, мимо сервера. Когда нет — через наш TURN-ретранслятор, который перекладывает уже зашифрованный поток и в него не заглядывает. Само установление связи (SDP и ICE) тоже едет внутри сквозного шифрования.
База на самом телефоне
Локальная база под SQLCipher, пароль лежит в аппаратном хранилище телефона. Плюс код блокировки, скрытие от скриншотов (в релизной сборке включено по умолчанию) и код-самоуничтожение, который вместо входа стирает данные.
Ключей у нас нет
Сервер не участвует в выработке ключей и не хранит приватные. Даже если базу сервера целиком заберут — переписку из неё не прочитать. Это не наша добрая воля, а свойство конструкции: расшифровать нечем.
Главное на этой странице
Что сервер видит, а что нет
Сервер здесь — почтовый ящик: держит зашифрованные конверты, пока адресат их не забрал. Ниже построчно, без округлений в нашу пользу. Жёлтым отмечено то, что мы ещё не закрыли.
| Данные | Сервер | Как именно |
|---|---|---|
| Текст сообщений | не видит | шифруется на устройстве; на сервере лежит только шифротекст |
| Файлы, фото, голосовые | не видит | шифруются тем же ключом сессии, что и текст |
| Содержимое звонков | не видит | DTLS-SRTP между устройствами; TURN пересылает шифропоток |
| Номер телефона, почта | не существует | при регистрации не спрашиваются — таких полей нет в базе |
| Список ваших контактов | не видит | хранится на телефоне, целиком на сервер не выгружается. Оговорка: включённый статус «в сети» заставляет приложение спрашивать сервер про ваших собеседников — тогда сервер видит этот набор. Поэтому статус по умолчанию выключен |
| Ваш ID и публичные ключи | видит | без них никто не может начать с вами шифрованную сессию |
| Ник и @имя, если задали | видит | необязательны; @имя можно скрыть из поиска, и это проверяет сервер, а не только приложение |
| Кто кому пишет | может определить | поле отправителя у конверта пустое, но рядом лежит служебный сертификат, который сервер пока читает. Шифрование этого сертификата написано и проверено, но в раздаваемой сборке не включено. Разбор ниже |
| Время отправки и доставки | видит | без метки времени невозможно ни доставить, ни удалить по сроку |
| Кто кому звонил и когда | видит | сервер сводит звонок, поэтому знает обе стороны. Запись живёт до 4 часов, маркер пропущенного звонка — 7 дней, и в нём обе стороны в открытом виде |
| Когда вы в сети | частично | в приложении переключатель по умолчанию выключен, и приложение тогда ничего не шлёт. Но на сервере у нового аккаунта этот флаг заводится включённым, и выключается он только когда вы впервые откроете этот экран — до тех пор вас спасает лишь то, что докладывать серверу нечего. «Был в сети» огрублён до минуты; пока статус включён, спросить может любой, кто знает ваш ID, кроме заблокированных |
| «Печатает…» | частично | по умолчанию выключено. Если включить, приложение раз в ~4 секунды сообщает серверу, кому вы пишете, в реальном времени |
| IP-адрес подключения | видит | неизбежно для любого сервера. Хотите скрыть — подключайтесь через VPN или Tor |
| Сервисы Google | не участвуют | уведомления идут по своему постоянному соединению, без FCM |
Сервер может определить, кто кому пишет
Это главная незакрытая вещь, и мы не спрячем её в сноску.
В записи на сервере поле «от кого» действительно пустое — sealed sender работает. Но рядом с конвертом едет сертификат отправителя: короткая подписанная справка, по которой получатель убеждается, что писали именно вы. Сейчас она едет открытой, и сервер её читает. Значит, сервер способен связать «этот аккаунт — с этим».
Есть и вторая причина, независимая от первой. Чтобы вернуть вам галочку «доставлено», сервер должен знать, кому её вернуть. Поэтому у непрочитанного сообщения он держит служебную ссылку на настоящего отправителя. Она обнуляется, когда приходит отметка о прочтении. Если квитки о прочтении выключены — живёт весь срок хранения сообщения.
Что готово, но не включено. Шифрование сертификата на получателя — после него сервер его не прочитает — написано, проверено и лежит в коде. 18 августа мы его включили и раскололи парк: сборки старше 11 августа не умели разбирать новый конверт, и у части людей перестало расшифровываться всё, включая ключи групп. 28 августа откатили. Оно вернётся, когда приложение научится узнавать, читает ли собеседник новый формат, — иначе история повторится.
Второй кирпич. Слепая маршрутизация квитков — чтобы галочка возвращалась по одноразовому токену, а не по имени отправителя — тоже написана: есть миграция базы и сквозной тест на настоящем Postgres. В раздаваемой сборке она выключена, потому что такую правку нельзя включать, не прогнав хотя бы раз на живом устройстве.
Пока это значит: содержимое вашей переписки серверу недоступно, а сам факт «этот аккаунт написал этому» — доступен. Мы не напишем «сервер слеп к отправителю», пока это не станет правдой на работающем сервере. Однажды на этой странице такая фраза уже стояла, будучи неправдой. Второй раз не будет.
Отправитель остаётся не только в таблице сообщений
Когда мы измерили это первый раз, оказалось, что смотрели в одно место, а отправитель жил в трёх. Чтобы не отправлять одно и то же дважды, сервер держит короткие служебные записи «это сообщение я уже принимал»: в Redis около суток и в базе — рядом с самим сообщением, то есть до 30 дней, если адресат так и не вышел в сеть.
Раньше в этих записях отправитель лежал открытым текстом, включая резервные копии Redis, где шифрования нет вовсе. Сейчас вместо него хранится HMAC. Это не полное слепление: у того, у кого есть и база, и серверный ключ, HMAC перебирается по списку аккаунтов, потому что идентификатор сообщения лежит рядом открытым. Закрыть это — большая правка протокола, и она не сделана.
IP-адрес и журналы сервера
Сервер видит адрес, с которого вы подключились, — иначе он не смог бы вам ответить. Он нужен для ограничения частоты запросов, а не для профилирования.
Сам мессенджер пишет в журнал метод, шаблон маршрута, код ответа, задержку и IP — именно шаблон, а не полный путь, иначе в журнал попадало бы, кто чей ключ запрашивал. Идентификатор аккаунта в обычные строки не пишется: он появляется только в редких строках о событиях безопасности вроде повторного использования токена.
Но перед ним стоит веб-сервер, и он аккуратность не соблюдает. Мы это замерили на работающей машине 3 сентября: входной сервер (Caddy) пишет в свой журнал полный адрес запроса вместе с IP клиента. Для запросов вида «забрать свою почту» там нет ничего лишнего, но у путей, в которых есть чужой идентификатор — например запрос ключей собеседника, — в журнал попадает и он, и адрес спросившего. То есть цель, ради которой бэкенд пишет шаблоны, на входе теряется. Журналы лежат в контейнере, ограничены по размеру, ротируются и наружу не отправляются, но это смягчение, а не решение. Чинится настройкой формата журнала на входном сервере; на момент этой правки не исправлено.
Журналы контейнеров ограничены по размеру и ротируются, наружу не отправляются.
Почему мы это проговариваем. В августе замер на живом сервере показал обратное: IP и идентификатор аккаунта писались в один и тот же файл, без ограничения по размеру и без срока, — то есть сервер держал запись о том, какой аккаунт подключался с какого адреса. Ровно то, чего вся эта страница обещает не хранить. В коде это исправлено; подтвердить, что на работающем сервере стоит именно эта версия, может только оператор.
Сроки
Сколько что лежит на сервере
Сервер не архив. Всё, что он держит, держится ради доставки и удаляется по расписанию, а не «по запросу в поддержку».
Пять минут после доставки — не округление. Это окно на переподключение: если телефон отвалился ровно в момент выдачи, сообщение успеет прийти второй раз. Потом строка исчезает вместе с квитками и служебной записью о ней.
Что удаляете вы
- Исчезающие сообщения. Таймер на чат: по истечении срока запись стирается с перезаписью, а не помечается удалённой. По умолчанию выключено — включаете вы.
- Удаление аккаунта. Каскадом стирает ваши строки на сервере: сообщения, вложения вместе с блобами, ключи, маркеры звонков.
- Код-самоуничтожение. Введённый вместо обычного кода блокировки, он стирает данные на телефоне и рассылает собеседникам команду стереть переписку у себя. У тех, кто офлайн, она срабатывает при следующем подключении. Это лучшее усилие, а не гарантия: скриншот чужого экрана мы отозвать не можем.
- Блокировка. Проверяется на сервере, а не только в приложении: новые сообщения от заблокированного не примутся, и статус «в сети» он тоже не увидит.
Про резервные копии. Снимки базы делаются, чтобы отказ диска не унёс аккаунты. Значит, удалённая строка может ещё какое-то время жить в снимке. Снимки шифруются — и в августе выяснилось, что из-за ошибки в скрипте часть их месяц ложилась открытыми. Ошибку нашли и исправили; рассказываем, потому что скрывать такое хуже, чем признать.
Уведомления
Без Google — и это проверяемо
Сообщения доставляет постоянное соединение самого приложения (WebSocket к нашему серверу), а держит его обычная фоновая служба Android. Никакого посредника между сервером и телефоном нет.
Полная честность: библиотека Firebase Messaging в APK лежит, и код для приёма «пинка» через неё написан. Но проект Firebase в сборке — заглушка с нулевым номером, а на сервере отправка выключена по умолчанию. Поэтому через серверы Google сейчас не уходит ни одного уведомления.
Если мы когда-нибудь включим этот путь как резервный, здесь появится строка об этом до включения, а не после. «Пинок» не будет содержать текста сообщения, и его можно будет выключить.
Ваши переключатели
Что можно выключить, и что это меняет
- Статус «в сети». Выключен по умолчанию, и это двусторонний тумблер: приложение перестаёт и объявлять вас, и спрашивать сервер про ваших собеседников. Именно второе и держит набор ваших контактов вне сервера.
- «Печатает…». Выключено по умолчанию. Включённое, оно раз в четыре секунды рассказывает серверу, кому вы пишете.
- Квитки о прочтении. Включены. Выключенные — экономят собеседнику знание, но продлевают жизнь служебной ссылки на отправителя: обнулять её нечему до самого истечения срока. Такой трейд-офф, и лучше знать о нём.
- Поиск по @имени: все / только контакты / никто. Запрет проверяет сервер и отвечает «не найдено» — так же, как на несуществующее имя.
- Кто может звонить и добавлять в группы — по тем же трём уровням.
- «Скрыть мой IP» в звонках. Гонит звонок только через TURN, чтобы собеседник не увидел ваш адрес. Ценой задержки, поэтому по умолчанию выключено.
- Исчезающие сообщения — таймер на чат или общий.
- Код блокировки и биометрия плюс отдельный код-самоуничтожение.
- Защита от снимков экрана. В релизной сборке включена.
Проверка
Не верьте странице — проверьте сами
- Число безопасности. Считается на устройстве из двух ключей — сервер в этом не участвует и подменить его не может. Сверьте с собеседником лично или голосом. Если его ключ сменится, приложение предупредит и снимет прежнюю отметку «проверен», а не сделает вид, что всё в порядке.
- Журнал сети внутри приложения. Экран, показывающий каждый исходящий запрос: адрес, размер, начало тела. Для переписки там всегда шифротекст. Это возможность увидеть, что уходит с телефона, а не обещание.
- Отпечаток файла и подписи. Хэш APK и отпечатки ключа опубликованы на главной. Сверяйте их через отдельный доверенный канал: страница, которую вам могли подменить, сама себя не подтверждает.
Внешнего аудита кода не было ни разу. Были наши собственные разборы, довольно злые — они лежат в репозитории вместе со всем найденным, включая то, что описано выше. Но это не то же самое, что независимая проверка, и выдавать одно за другое мы не будем.
Закон
Если у оператора что-то потребуют
Оператор может отдать только то, что у сервера есть: идентификаторы аккаунтов, метаданные маршрутизации в пределах срока хранения, адреса подключений из журналов — и, пока не закрыто описанное выше, связь «кто кому писал» по непрочитанным сообщениям.
Содержимое сообщений, звонков и вложений оператор отдать не может: оно зашифровано между устройствами, а ключей у сервера нет. Это не позиция, которую можно передумать под давлением, — расшифровать физически нечем.
Обязательств о прозрачности под конкретную юрисдикцию здесь пока нет: их надо писать с юристом, а не сочинять. Лицензии и пользовательского соглашения у проекта тоже пока нет — это честный пробел, а не забытая формальность.
Возраст
Приложение не предназначено для детей младше возраста, установленного вашей юрисдикцией (обычно 13 или 16 лет). Формулировку надо уточнить с юристом — пока это она.
Связь
Как достать оператора
Почтового сервера у Signet нет, и публиковать адрес мы не хотим: он соберёт спам к проекту, который ведёт один человек. Замысел был простой — добавить контакт @signet в приложении и написать, чтобы вопрос о приватности сам не утёк по дороге.
Прямо сейчас это не работает. Имя @signet попало в серверный список зарезервированных, и занять его не может никто, включая оператора. Это наш собственный баг, он в списке на исправление. Пока он жив, надёжного публичного канала связи с оператором нет: пишите тому, кто дал вам приложение или ссылку на него.
Если эта страница изменится
Существенные изменения мы объявим в приложении и на странице загрузки, с новой датой сверху. Правки в сторону «звучит приятнее» без изменений в коде мы не делаем: страница меняется, когда меняется то, что она описывает.