Справочник / Доказательства
Формат доказательств
Содержимое подписанного ZIP-архива, типы записей, подтверждения обработки, профили пользователей, внешние копии и офлайн-проверка.
Наблюдение не является выводом. Идентификатор отправителя не соответствует реальной личности. Источником информации является обновление сервиса, видимое пользователям аккаунта; Telegram не подписывает криптографически эти сохраненные записи для сторонних следователей.
Что подлежит подписанию#
| Материалы | Защита | Что следует сохранять |
|---|---|---|
| Каждая запись в журнале, включая оперативные события | Цепочка SHA-256 и подпись Ed25519 для каждого события | Исходный events.jsonl — отпечаток доверенного ключа — и сохраненная контрольная точка |
| Содержимое ZIP-архива с доказательствами | manifest.sig подписывает канонический манифест, в котором перечислены хэши файлов с содержимым |
Полный ZIP-архив, включая манифест и подпись |
| Сохраненные вложения | SHA-256 и количество байтов в подписанном событии media.saved; хеш файла в подписанном манифесте ZIP |
Исходные байты внутри проверенного ZIP-архива |
| Checkpoint | Подпись Ed25519, охватывающая длину журнала, хеш заголовка, открытый ключ и время создания | Независимая копия, сохраненная до внесения спорного изменения |
| Квитанция об отправке | Отдельно подписанные данные сбора; также включены в подписанное событие process.started |
Полученные данные и соответствующий журнал; показатели указаны по собственным данным |
| Автономный файл в формате CSV или HTML | Отсутствие автономной криптографической подписи; одних только хешей событий недостаточно | Для проверки целостности используйте точную копию, содержащуюся в проверенном ZIP-файле |
| Скриншоты, распечатки или PDF-файлы, сгенерированные браузером | В производном материале не должно быть упоминания о TgWitness | Сохраните исходный проверенный пакет и задокументируйте процесс создания производного файла |
Перед генерацией каждого формата экспорта сборщик проверяет подписи журнала. Данная проверка источника не создаёт подпись на отдельно загруженном файле CSV или HTML. Действительная подпись события в формате JSONL также не предоставляет байты вложения и не подтверждает самостоятельно, что был предоставлен весь наблюдаемый журнал.
Передача расследования#
- Укажите в заметках по делу номер дела, оператора, числовой идентификатор аккаунта в Telegram, выбранные источники, политику сбора данных и период сбора. TgWitness сохраняет результаты наблюдений; управление назначением дел и записями о хранении данных осуществляется вне приложения. Уточните намеченную конфигурацию сбора данных в ходе процедуры утверждения в режиме реального времени.
- Перед тем как полагаться на экспортированные данные, самостоятельно сохраните отпечаток открытого ключа рабочей среды. Во время сбора данных сохраняйте подписанные контрольные точки вне коллектора. Фиксируйте прерывания процесса и ограничения видимости учетной записи.
- Экспортируйте подписанный ZIP-файл и сохраните подписанную квитанцию о запуске. Используйте контрольную точку, расположенную на границе экспортируемого журнала или перед ней. Более поздняя контрольная точка может правильно отклонить более ранний экспорт как слишком короткий. Экспорт включает полный журнал рабочей области, независимо от фильтров панели; ознакомьтесь с материалом перед его передачей.
-
Попросите получателя проверить ZIP-архив с помощью надёжной копии программы проверки и независимо предоставленного отпечатка/контрольной точки. Из надёжного репозитория с активной средой Python:
python -m tgwitness.verify evidence.zip --fingerprint TRUSTED_PUBLIC_KEY_SHA256 --checkpoint retained-checkpoint.jsonПри успешном выполнении выводятся отчеты
key_pinned: trueиcheckpoint_checked: true, если оба входных значения предоставлены и приняты. Сохраните результат проверки.For a handover requiring the final exported record to be witnessed, use `--witness witness.zip --witness-fingerprint TRUSTED_WITNESS_SHA256 --require-witness`. This refuses an export with an unwitnessed tail. See the [witness handover procedure](WITNESS.md#require-a-witnessed-export-boundary).- Зафиксируйте в вашем протоколе хранения SHA-256 архива, границы экспорта, дату передачи, отправителя и получателя. Сохраняйте исходный пакет в неизменном виде и работайте с копиями. Передавайте файлы с доказательствами, а не каталог личных данных приложения, который также содержит сеансы учетных записей и секретные ключи подписи. Для передачи экспортный файл можно поместить в ZIP-архив с защитой по паролю AES-256. Пароль обеспечивает лишь конфиденциальность и не сохраняется; получатель извлекает архив и проверяет содержащийся в нём подписанный экспортный файл, который остаётся неизменённым.
- Если требуется независимая привязка ко времени, следуйте процедуре, изложенной в RFC 3161, и сохраните запрос, контрольную точку, информацию о доверенном центре сертификации, а также проверенный ответ центра сертификации. Сам по себе запрос не обеспечивает получение временной метки.
Успешная верификация подтверждает целостность данных относительно доверенного ключа сборщика и сохраненных границ. Подлинность источника, полная доставка сообщений Telegram, достоверное время и допустимость в суде требуют отдельных доказательств. Данная версия не прошла квалификацию в реальных условиях Telegram или независимую экспертизу в области криминалистики и безопасности.
Скопированный ключ сборщика может подписать сфабрикованный журнал-замену. Проверка по отношению к независимо сохраненной контрольной точке или записи-свидетелю позволяет обнаружить изменение раннего префикса; сама по себе проверка подписи этого сделать не может. «Свидетель» фиксирует то, что представил сборщик, поэтому он не устанавливает независимо достоверность записей, сфабрикованных до их первой внешней контрольной точки. Отчёты о развёртывании в облаке проверяют конфигурацию и отчёты сборщика о показателях; они не подтверждают, что закрытый ключ никогда не был скопирован во время начальной настройки.
Уведомления, отправляемые через Apprise, содержат названия рабочих пространств и чатов, а также количество сообщений; краткие выдержки из удалённых и отредактированных сообщений добавляются только в том случае, если оператор включит эту функцию (по умолчанию она отключена). Они служат лишь сигналом для удобства, а не доказательством: доставка не гарантируется, и только журнал и его подписанные экспортные файлы фиксируют то, что было зафиксировано. При использовании прокси рабочей зоны уведомления проходят по тому же маршруту; услуги, которые не могут использовать этот маршрут, а также маршруты MTProxy, отклоняются.
Канонизация событий#
Входные данные хеша состоят именно из следующих полей:
seq, observed_at, source_at, kind, chat_id, message_id, actor_id, payload, previous_hash
Сериализация должна осуществляться с использованием JSON, совместимого с Python, в кодировке UTF-8, с отсортированными ключами объектов, без ASCII-эскейпинга, без незначительных пробелов и без значений NaN/бесконечности:
json.dumps(value, ensure_ascii=False, sort_keys=True,
separators=(",", ":"), allow_nan=False).encode("utf-8")
Хеш события формируется на основе SHA-256 этих байтов. Подпись создается с помощью алгоритма Ed25519 над 32 исходными байтами хеша, а затем кодируется в Base64. Первый предыдущий хеш (previous_hash) состоит из 64 нулей. Порядковые номера начинаются с 1 и увеличиваются на 1. Все события, включая операционные, составляют одну цепочку. Подавление дубликатов доставки отсутствует: повторные наблюдения представляют собой отдельные подтверждения получения, а не утверждение о различных действиях в Telegram.
Исходные даты Telegram представляют собой строки в формате ISO; двоичные поля преобразуются в объекты, содержащие bytes_base64. Текст сообщения, сущности, дескрипторы мультимедиа, метаданные ответов, реакции и действия сервиса сохраняются в исходных метаданных сообщения, если они были предоставлены.
observed_at — это системное время сбора данных в формате UTC. source_at — это указанная дата из Telegram, если она доступна. Уведомления об удалении не содержат точного времени удаления, поэтому source_at остается нулевым. Порядок получения данных не обязательно соответствует порядку событий в источнике. В моментальных снимках истории используются более старые даты источника, но текущее время наблюдения.
Семантика участников#
message.new actor_id — это отправитель сообщения. В поле message.edited отсутствует предполагаемый редактор; поле payload.sender_id фиксирует отправителя наблюдаемого сообщения. Удаление actor_id остаётся нулевым. Сообщения службы членства сохраняют отправителя и тип действия, не преобразуя каждое удаление в добровольный выход из группы. Необработанные обновления участников сохраняют actor_id в том виде, в котором он был предоставлен. Снимки реакций не придумывают участника, внесшего изменения.
Уведомления об удалении для личных чатов и обычных групп содержат только идентификаторы сообщений. Эти чаты используют единую последовательность идентификаторов для всей учётной записи, поэтому каждый идентификатор идентифицирует одно конкретное сообщение данной учётной записи. Если сообщение с данным идентификатором ранее было сохранено в данном журнале, его удаление фиксируется в данном чате как message.deleted с именем метода payload.chat_resolution. Идентификаторы, которые никогда не сохранялись, хранятся как deletion.unscoped без chat_id; никаких предположений не делается. Каналы и супергруппы нумеруют сообщения по чатам и никогда не сопоставляются таким образом. Если удалённое сообщение было отправлено наблюдаемой учётной записью, payload.deleted_message_was_outgoing принимает значение true; информация об удаляющем пользователе по-прежнему не предоставляется.
Объём охвата: непрерывность, пробелы и незафиксированные идентификаторы#
Каждый подписанный ZIP-файл содержит файл coverage.json, HTML-отчёт открывается с той же сводкой, а файл
verify.py пересчитывает её на основе файла events.jsonl, а не доверяет исходному файлу:
- Непрерывное наблюдение с момента X до момента Y. Период начинается с кода
observation.startedи заканчивается при паузе, остановке, потере соединения с Telegram, выходе из системы, запуске процесса без упорядоченной остановки или при отсутствии записей в течение более трёх минут во время наблюдения (сигналы о работоспособности записываются каждую минуту, поэтому отсутствие записей означает, что процесс остановился, завис или компьютер перешел в спящий режим). При изменении интервала сигналов о работоспособности в разделе «Параметры» каждый сигнал фиксирует это изменение, и допустимое время отсутствия записей становится равным трём интервалам, но никогда не менее трёх минут. - В списке пробелов указывается временной интервал между периодами с указанием причины. Пробел, остающийся незаполненным на момент последней
записи, обозначается как
not_resumed_by_last_record. - Идентификаторы сообщений не фиксируются. В случае каналов и супергрупп, в которых сообщения нумеруются по чату, пропущенные идентификаторы между зафиксированными указываются в виде диапазонов. Они отражаются как «не зафиксированы» — удаленные, никогда не доставленные или находящиеся за пределами сохраненной истории — но ни в коем случае не как «удаленные». В личных чатах и обычных группах используется единая для всей учётной записи нумерация, поэтому пробелы в ней ничего не значат и не указываются.
- Уведомления о пропусках на уровне чата (например, запрос Telegram о восстановлении разницы в одном канале) учитываются как заметки; они не прерывают общее охват.
Описание охвата указывает, что именно зафиксировал данный сборщик данных. Это не является доказательством того, что Telegram доставил все обновления в течение непрерывного периода времени.
Продюсер#
Подписанный манифест ZIP-архивов с доказательствами, экспортов чатов, журналов свидетелей и файлов с
профилями лиц содержит producer
: название программного обеспечения, версию, проект (PhishDestroy),
домашнюю страницу и репозиторий исходного кода. В отчёте в формате HTML отображается та же строка, а verify.py
выводит её в качестве части проверенных данных. Архивы, созданные до появления этого поля, проверяются так же, как
и ранее, и в отчёте указываются как не содержащие сведения о создателе.
Профили пользователей#
Файл профиля (tgwitness-dossier-v1, JSON) формируется по запросу на основе записей, уже имеющихся в
журнале для одного чата; никакие данные из Telegram не извлекаются, а содержимое профиля никогда
не записывается в журнал (включение и выключение профилей фиксируется как dossier.changed).
Для каждого пользователя, у которого сохранено сообщение, указываются имя и история имений, флаги Telegram
(бот, мошенничество, фейк, премиум, подтверждённый, ограниченный доступ, удалённый) на момент сохранения,
идентификаторы фотографий, SHA-256 и перцептивный хеш (pHash, совместимый с imagehash.phash)
аватара из локального кэша аватаров с похожими аватарами, активность (первое и последнее сообщение,
количество сообщений, отредактированные и удалённые публикации, сообщения по часам UTC), кто кому отвечает, другие чаты
в этом журнале, в которых данный пользователь писал, а также упомянутые кошельки (BTC, EVM, TRON, TON, LTC,
DOGE, XMR, SOL; адреса в формате Base58Check проходят проверку контрольной суммы), номера телефонов, имена пользователей и
ссылки, включая ссылки, скрытые за текстом.
Каждый факт сопровождается указанием записей журнала (seq), из которых он взят, а record_hashes содержит
хэш каждой упомянутой записи. Заявление подписано ключом рабочей области:
python verify.py tgwitness-dossier-CHAT.json --fingerprint TRUSTED_SHA256 --evidence tgwitness-evidence.zip
Проверяет подпись, верифицирует сам экспорт доказательств (подпись, цепочку хешей и файлы) а также наличие каждой упомянутой записи в неизменённом виде в данном экспорте того же рабочего пространства. Хеши аватаров помечаются как полученные из локального кэша (а не из записей журнала). Упоминания представляют собой совпадения по шаблону — это подсказки для проверки, а не подтверждённые факты. Профили включаются для каждого чата, могут экспортироваться в виде ZIP-архива с шифрованием AES-256 и паролем, а также удаляются при отключении или при удалении чата из источников.
Независимый свидетель#
Журнал «Witness» (tgwitness-witness-v1) и сообщения в его канале сверяются с
экспортом доказательств с помощью verify.py --witness … --channel …; см. раздел «Независимый свидетель».
Манифест и контрольные точки#
Файл manifest.json содержит информацию о формате, времени экспорта, открытом ключе, отпечатке, длине журнала,
хеше начала, области действия, создателе, ограничениях, а также SHA-256 каждого элемента содержимого, кроме
самих manifest.json и manifest.sig.
Файл manifest.sig представляет собой подпись Ed25519 в кодировке base64, наложенную на канонический JSON-манифест.
Проверяющее устройство отклоняет неожиданные или отсутствующие элементы, дубликаты имен, повреждённые файлы,
нарушенную последовательность или цепочку, недействительные подписи, а также несоответствие предоставленной контрольной точке.
Оно никогда не извлекает пути к архивам. Общий объём некомпрессированных данных ограничен 4 ГиБ;
архивы --max-gib N, созданные с увеличенным пределом параметров, могут иметь больший размер.
Получите код верификатора из надёжного источника или из проверенной независимой копии. Верификатор, находящийся внутри ненадежного архива, представляет собой исполняемый материал, предоставленный автором данного архива; его наличие служит для удобства переноса, а не является независимым основанием для доверия.
Контрольная точка подписывает заявление, содержащее открытый ключ, длину журнала, хеш-код начала и время создания. Верификатор может проверить, содержит ли более поздний архив тот же префикс. Сохраняйте контрольную точку вне коллектора до внесения спорного изменения: злоумышленник, контролирующий как архив, так и контрольную точку, может заменить и то, и другое.
Действительная подпись, полученная с помощью незакреплённого ключа, подтверждает лишь внутреннюю согласованность данных. Даже закреплённый ключ не может подтвердить достоверность исходного содержания, если сборщик данных или ключ были скомпрометированы до начала записи. Внешняя маркировка временем и надёжный сбор данных являются отдельными требованиями. TgWitness не гарантирует допустимость доказательств в суде или их криминалистическую сертификацию.
Вложения#
Файлы идентифицируются по хешу SHA-256 в каталоге media/. Событие media.saved связывает хеш и длину в байтах с конкретным событием сообщения. Исходные имена файлов являются метаданными, а не локальными путями. Байты мультимедиа загружаются асинхронно, поэтому немедленное удаление может помешать их фиксации. В качестве результатов отображаются: отключенный сбор данных, файлы чрезмерного или неизвестного размера, сбои при загрузке и прерванные загрузки. Сбой процесса может привести к появлению неимеющих ссылок неполных файлов; они не включаются в экспортируемые данные.
Экспортер в формате ZIP сверяет сохраненные медиафайлы с их именами. Экспорт в форматы JSONL, CSV и HTML проверяет сигнатуры событий, но не передаёт байты медиафайлов. Производные отчёты предназначены для удобства; файл events.jsonl является авторитетным представлением событий.
Надежный сбор и обработка подтверждений (0.2)#
Обработка медиафайла и фиксация события сообщения осуществляются в рамках одной транзакции. Задание сохраняет исходный дескриптор сообщения Telegram; подписанное наблюдение связывает его SHA-256, учётную запись и политику размера. При восстановлении эта привязка проверяется перед загрузкой. Система никогда не извлекает текущее сообщение и незаметно заменяет его более новым вложением. Прерванные задания повторяются, в то время как постоянный сбой остаётся явным результатом.
Каждая рабочая область имеет собственный журнал и идентификатор подписи. Событие process.started содержит идентификатор запуска, время по локальным часам, версии зависимостей, хэши исходных файлов, исходные данные об учётной записи/области действия, а также настройки записи. Сигналы пульсации включают идентификатор запуска, монотонное время и состояние очереди. Квитанцию о процессе также можно загрузить в виде отдельно подписанного отчёта. Данные об объёме файлов предоставляются самими пользователями и не являются достоверной аппаратной аттестацией.
Автоматические контрольные точки сохраняются локально при запуске, каждые пять минут в ходе наблюдения (Параметры → «Подписанная контрольная точка каждые») и при упорядоченном завершении работы. При проверке при запуске и экспорте журнал сравнивается с последней сохраненной локальной контрольной точкой. Это позволяет обнаружить откат базы данных, если контрольная точка сохранилась; оператор, контролирующий и то, и другое, по-прежнему может заменить и то, и другое. Независимое хранение данных и внешние доверенные временные метки остаются отдельными требованиями.
После перезапуска возобновляется сохраненная позиция обновления Telegram (catch_up_from в
observation.started), и запрашиваются пропущенные обновления. Периодическая повторная проверка фиксирует
message.recovered для пропущенных сообщений и message.missing_on_recheck, когда Telegram больше
не возвращает сохраненное сообщение; последнее не является уведомлением об удалении и не указывает ни лицо, удалившее сообщение, ни время.
Внесайтовое копирование и восстановление (S3)#
Внесайтовая копия (функция «Экспорт», по умолчанию отключена) загружает фрагменты журнала, сохраненные файлы, контрольные точки
с их временными метками, а также готовые экспорты чатов в хранилище, совместимое с S3, зашифрованные с помощью
AES-256-GCM перед загрузкой с использованием ключа, хранящегося в хранилище рабочей области; применяется функция удержания Object Lock,
если это поддерживается хранилищем. Без загруженного ключа копия не подлежит чтению. Восстановление и проверка
осуществляются с помощью python -m tgwitness.replica restore --key-file KEY.json --out DIR.
Для восстановления требуется пустой обычный каталог. Загруженные и расшифрованные объекты остаются в частном временном хранилище до тех пор, пока не будет проверен весь журнал и каждая сохраненная контрольная точка. Небезопасные пути к объектам, несогласованные диапазоны сегментов и журналы, длина которых меньше контрольной точки, отклоняются; в случае неудачной проверки восстановленные файлы не публикуются. Проверки срока хранения сравнивают возвращённый режим Object Lock и дату с крайним сроком, отправленным при загрузке (допуск на округление составляет одну секунду). Истекший, недействительный или сокращённый крайний срок не считается проверенным. Статус указывает на выбранный объект, срок хранения которого был считан обратно для данного цикла загрузки.
Ход копирования определяется в зависимости от места назначения и ключа шифрования. Изменение конечной точки, хранилища или префикса запускает полное копирование локально сохраненного журнала, мультимедиа и контрольных точек в указанное место назначения. Старые данные, не охваченные текущим процессом копирования, сохраняются, но воспроизводятся один раз после обновления. Исторические экспорты чатов, уже удалённые из локальной папки «Исходящие», остаются в прежнем месте назначения.
Отсутствие или повреждение локальных медиафайлов фиксируется как ошибка текущего прохода, при этом курсор медиафайлов остаётся перед этим местом, чтобы файл был повторно обработан в следующем проходе; файлы, контрольные точки и экспортированные данные, следующие за ним, по-прежнему копируются. При восстановлении все ссылки на сохраненные медиафайлы сверяются с расшифрованными хешами и зафиксированными размерами. Идентичные перекрывающиеся сегменты журнала от прерванных загрузок дедуплицируются; конфликтующие перекрытия отбрасываются. Контрольные точки, созданные во время загрузки, откладываются до тех пор, пока охватываемые ими записи журнала не будут скопированы, поэтому завершённый проход не публикует контрольную точку раньше, чем соответствующая запись в журнале.
Потоковый экспорт моментальных снимков#
При потоковом экспорте используется стабильный снимковый файл чтения SQLite. Его начало может оказаться более старым, чем текущий активный журнал к моменту завершения загрузки. Контрольная точка, созданная после этого снимка, может правильно показывать, что архив короче; сравнивайте с контрольной точкой, расположенной на уровне экспортируемого префикса или перед ним, а не с произвольной более поздней контрольной точкой.
Подготовка RFC 3161 и проверка ответов (0.2)#
В режиме «Доказательства» (по умолчанию отключен) отправляется только хеш SHA-256 каждой подписанной контрольной точки в указанные
авторитетные источники по стандарту RFC 3161 и календари OpenTimestamps через маршрут рабочей области, но ни в коем случае не через MTProxy.
Ответы хранятся в формате checkpoints/anchors/, экспортируются и проверяются с помощью verify.py (--tsa-ca проверяет
подпись TSA; подтверждение доказательств OpenTimestamps осуществляется с помощью ots upgrade и ots verify).
Панель подготавливает архив запросов, содержащий канонические байты файла checkpoint.json, отпечаток сообщения с хэшем SHA-256 и случайный нонс в файле timestamp.tsq, а также контрольные суммы и инструкции. Сетевые запросы не осуществляются. Подготовленный архив не является доверенной временной меткой.
python -m tgwitness.anchor verify дважды вызывает OpenSSL: один раз для проверки
байтов контрольной точки и один раз для проверки исходного запроса. Требуется явно указать файл доверенного центра сертификации;
включённые сертификаты автоматически не считаются доверенными. Проверка запроса является опциональной в
командной строке, поэтому сохраните и укажите параметр `--request` для проверки нонса. Результат указывает, была ли
проведена проверка. Подпись контрольной точки сборщика и журнал по-прежнему необходимо проверять
отдельно с помощью доверенного отпечатка сборщика.
Текущий верификатор не получает информацию об отзыве сертификатов и не обеспечивает долгосрочную проверку архивных данных после истечения срока действия сертификата. Не следует приравнивать успешную проверку подписи к квалифицированной временной метке или юридической допустимости. В ходе разработки не осуществлялось взаимодействие с реальной независимой организацией TSA. См. процедуру.