5.4 KiB
Прозрачность счётчика пользователей
Версия: 2026-05-19
Что мы доказываем
Число «Уникальных пользователей» на montana.quest/vpn/ — не выдумано.
Что мы НЕ публикуем
IP-адреса пользователей. Это PII (персональные данные) — публиковать их незаконно (GDPR / 152-ФЗ) и аморально.
Как доказательство работает
-
На узле Helsinki в
/var/lib/montana-vpn-stats/unique-ips.txtнакапливается список IP, когда-либо подключавшихся к VPN (из xray access.log). Файл root:root 600, не доступен публично. -
Каждую минуту скрипт
/opt/montana-vpn-stats/transparency-sign.py:- читает список IP
- сортирует
- вычисляет
sha256(joined-with-LF)→ merkle_root - подписывает snapshot
{ts_utc, unique_users, merkle_root, algorithm}ключом ed25519 - публикует:
https://montana.quest/vpn/transparency.json— последний snapshothttps://montana.quest/vpn/transparency-log.txt— append-only лог всех snapshot'ов
-
Публичный ключ подписи:
d9a8bf07871d35c8e85f7de4a9b62896c330ba0987732468515c7bda8bb4adde(ed25519). Лежит здесь и в репозитории. Приватный ключ — только на узле, 600 root.
Что может проверить аудитор без доступа к серверу
| Свойство | Как проверить |
|---|---|
| Подпись валидна | verify-transparency.sh проверяет ed25519 над snapshot |
| Публичный ключ не сменили | сравнить с публикуемым в этом репозитории |
| Число не подкручивается вниз | transparency-log.txt — append-only, аудитор скачивает последние N снимков, проверяет монотонность |
| Snapshot timestamp реальный | сравнить ts_utc с моментом скачивания (расхождение ≤ 60s) |
| Один и тот же merkle root = одни и те же IPы | повторный merkle root между snapshots = новых IP нет |
Что аудитор НЕ может узнать
- Конкретные IP пользователей (они зашифрованы в merkle root).
- Страну/время подключения отдельного пользователя.
Чтобы доказать что конкретный IP в множестве — нужен сам IP (известен только владельцу) + полный список (raw unique-ips.txt доступен только под NDA на аудит, не публично).
Запуск проверки
bash scripts/verify-transparency.sh
Скрипт:
- Скачивает
https://montana.quest/vpn/transparency.json. - Проверяет ed25519-подпись с известного
EXPECTED_PUBKEY. - Скачивает
https://montana.quest/vpn/transparency-log.txt. - Проверяет монотонность роста за последние 50 снимков.
- Выводит зелёные галки и текущее число.
Ограничения текущей реализации
- Anti-tamper только в пределах подписи. Атакующий с доступом к privateKey может выдавать любое число. Защита: ключ 600 root + сервер изолирован.
- Нет on-chain anchor. При желании можно anchored daily snapshot в Bitcoin через OpenTimestamps — это даст proof что snapshot существовал не позднее timestamp'а в чейне. Roadmap.
- IP = пользователь — приближение. Один человек с двух IP считается как 2; несколько человек за одним NAT-IP считаются как 1. Это верхняя оценка уникальных для NAT и нижняя для multi-device. Точнее без trackable user-ID (что = приватность ↓).
- Уязвимость к ротации файла. Если
unique-ips.txtкорраптится — счётчик откатывается. Защита: append-only лог сохраняет историю.
Полный список секретов
/etc/montana/transparency-privkey(Moscow, 600 root) — ed25519 приватный ключ подписи.- Только этот хост может подписывать. При компрометации — генерация нового keypair, обновление публичного ключа в репо + публикация incident notice.
Roadmap
- P1: Bitcoin OpenTimestamps anchoring каждый день в 00:00 UTC.
- P2: Migration на cryptographic accumulator (RSA / Merkle tree) для proof-of-membership без раскрытия списка.
- P3: Multi-party signing (2 of 3 узлов подписывают) — устраняет single point of trust на Moscow privateKey.