Перейти к содержимому

Машины и баны

Забанить аккаунт — значит попросить нарушителя завести новый. Laminara умеет узнавать компьютер, с которого заходят, и банить его: аккаунт, машину или группу связанных машин.

Включение

{
"hwid": {
"mode": "observe",
"saltPath": "/var/lib/laminara/hwid.salt",
"ticketSecretPath": "/var/lib/laminara/hwid-ticket.key",
"store": {
"backend": "sql",
"config": { "driver": "sqlite", "dsn": "/var/lib/laminara/machines.db" }
}
}
}

Пересоберите лаунчер: client-config положит в него соль, и без неё лаунчер вообще ничего не измеряет.

mode Что делает
off Ничего. Лаунчер не собирает данные.
observe Записывает машины, никого не блокирует. По умолчанию.
enforce Блокирует по банам.

Как узнаётся машина

Лаунчер измеряет 8–14 свойств: UUID материнской платы, серийники дисков и платы, machine-id системы, MAC постоянных сетевых карт, модель видеокарты и процессора, объём памяти, идентификатор установки ОС. Каждое хешируется солью прямо на компьютере игрока — на сервер уходят только 16-байтовые дайджесты, сырых значений в протоколе нет вообще (в контракте просто нет такого поля).

Плюс лаунчер держит ключ машины. Он бывает двух видов, и разница честно сообщается серверу флагом PLATFORM_KEY_FALLBACK:

  • Аппаратный (TPM). Ключ живёт в чипе, приватная часть наружу не выходит никогда, чип отказывается его дублировать. На Linux это primary key, который TPM заново выводит из своего собственного сида: нигде ничего не хранится, удалять нечего, переустановка системы его не теряет, скопировать на другой компьютер невозможно. Вес — 40 (якорь).
  • Программный. Пара Ed25519 сразу в двух местах: хранилище паролей ОС и скрытый файл в домашней папке, восстанавливается из любого уцелевшего. Побеждает «удалить папку лаунчера» — то, что пробуют первым, — но копируется и не переживает форматирование. Вес — 15.

Лаунчер сам берёт лучшее из доступного, настраивать ничего не нужно.

Где аппаратный ключ работает

ОС Состояние
Linux Работает, проверено на живом TPM 2.0. Но /dev/tpmrm0 имеет права root:tss 0660 — игроку нужно быть в группе tss (sudo usermod -aG tss $USER один раз), иначе тихо откатываемся на программный ключ.
Windows Через Microsoft Platform Crypto Provider, прав администратора не нужно. Написано, но на живом железе не проверялось.
macOS Пока нет. Создание ключа в Secure Enclave не имеет консольного пути и требует биндингов Security.framework, которые здесь не собрать и не запустить. Остаётся программный ключ — на macOS Keychain и так надёжен.

Совпадение считается по очкам, а не по равенству — реальная машина меняется:

Вес Сигналы
40 UUID платы, UUID платформы, аппаратный ключ машины (в виртуалке — вдвое меньше)
15 серийник платы, серийник диска (до двух), machine-id, программный ключ машины
5 MAC, том, видеокарта, процессор, память, имя хоста
та же машина ⟸ очки ≥ 45 и совпало ≥ 2 разных вида
очки ≥ 25 ⟸ новая машина, но в том же кластере (связанный компьютер)
меньше ⟸ новая машина, новый кластер

Одного якоря (40) намеренно не хватает: партии материнок уезжают с завода с одинаковым UUID. Видеокарта + процессор + MAC не решают никогда — тысячи людей делят модель.

Автодемоция. Дайджест, встреченный больше чем на 25 машинах, перестаёт считаться уликой. Это само убирает нули в прошивке, серийники 0000_0000 у USB-переходников и клонированные образы виртуалок — без ручных чёрных списков.

Баны

ban <ник> <причина...> [--account|--machine <id>|--cluster <id>] [--days N|--permanent] [--yes]
bans список активных
bans LM-7F3A карточка одного бана
bans lift LM-7F3A снять
machines <ник> машины игрока
machines show <id> машина, её аккаунты и кластер
machines trust <id> пометить машину доверенной (семейный ПК, интернет-кафе)
machines prune вычистить давно неактивные

Без флага области ban выбирает её сам и печатает выбор: кластер, если машины игрока лежат в одном небольшом кластере без доверенных машин, иначе аккаунт.

У каждого бана есть референс-код вида LM-7F3A. Игрок называет его в тикете, вы делаете bans LM-7F3A и видите кто, когда, за что и в какой области. Это разница между отвечаемым и неотвечаемым обращением.

Аппаратные баны истекают (по умолчанию 90 дней), аккаунтные — постоянные. Компьютеры продают и передают; вечный бан по железу копит ложные срабатывания бесконечно.

Если бан заденет больше трёх разных аккаунтов, команда откажется его применять и покажет список — придётся подтвердить --yes. Семейный ПК, интернет-кафе и школьный класс из одного образа реально выглядят одной машиной; machines trust помечает такие, и они больше не попадают под автоматический выбор кластера.

Где проверяется

  1. Вход в лаунчер — при бане сессия отзывается сразу же.
  2. Перед запуском игры и при восстановлении сессии — так бан, выданный посреди установки, всё же останавливает игрока.
  3. /yggdrasil/authserver/authenticate — вход в игру.
  4. /sessionserver/.../join — коннект к серверу, ловит бан посреди сессии.

Пункт 3 — несущий. Сторонний лаунчер с authlib-injector ходит туда напрямую, минуя весь API Laminara. Включите "requireLauncher": true, и вход в игру потребует короткоживущий тикет, который выдаётся только через нормальный вход в лаунчер.

Настройки

modestring

off · observe (по умолчанию) · enforce.

saltPathstring

Файл с 32 байтами соли. Создаётся сам. Смена соли обнуляет всю базу машин и требует пересборки лаунчеров.

ticketSecretPathstring

Ключ для тикетов входа в игру.

storeobject

memory (по умолчанию, не переживает перезапуск) или sql с driver = sqlite/postgres/mysql.

requireReportboolean

Отказывать входу вообще без отчёта о машине. По умолчанию false.

requireChallengeboolean

Требовать ответ на свежий одноразовый nonce. По умолчанию включено в enforce.

requireLauncherboolean

Требовать тикет на входе в игру. Закрывает обход сторонним лаунчером.

requireHardwareKeyboolean

Пускать только с ключом в TPM. Самая строгая настройка — см. предупреждение выше.

minScore · minKinds · clusterScorenumber

Пороги совпадения: 45, 2, 25.

fanOutLimitnumber

Со скольких машин дайджест перестаёт считаться уликой. По умолчанию 25.

maxClusterSizenumber

До какого размера кластера ban готов выбрать область «кластер» сам. По умолчанию 8.

vmPolicystring

allow · flag (по умолчанию) · deny.

hardwareBanTTLstring

Срок аппаратного бана. По умолчанию 2160h (90 дней).

retention · ipRetentionstring

Сколько хранить неактивные машины (4320h) и IP (720h).

Приватность

Сырых значений в протоколе нет — это ограничение контракта, а не обещание. Соль запечена в лаунчер, значит она есть и у игрока: высокоэнтропийные входы (UUID прошивки, серийник диска) необратимы по-настоящему, низкоэнтропийные (модель процессора, объём памяти) переберёт любой, у кого есть соль. Соль даёт ровно две вещи: Laminara никогда не хранит и не передаёт сырой серийник, и украденная база бесполезна для сопоставления с базой другого сервера.

Из соображений давности IP хранится 30 дней и только последний, машины без активности 180 дней вычищаются целиком (machines prune).

Экран входа прямо говорит игроку, что отпечаток собирается. Прятать это бессмысленно — лаунчер открытый, — и именно скрытность злит людей.

Что она не ловит

  • Пропатченный лаунчер. Сбор идёт на машине игрока; заголовок версии клиент заявляет сам. Что реально даёт порог версии — при каждом релизе патч приходится накладывать заново. Это не проверка целостности.
  • Коммерческие спуферы уровня ядра (~$20–50/мес на рынке читов) подменяют SMBIOS, дисковые запросы и MAC разом. Из пользовательского пространства с этим ничего не сделать.
  • Программный ключ можно скопировать. Он переживает переустановку лаунчера, но переносится на чужой компьютер и не переживает форматирование. Аппаратный (TPM) этих слабостей не имеет — но он есть не у всех, см. таблицу выше.
  • Свежая виртуалка стоит 10 минут. Определяется и помечается, блокируется только при vmPolicy: deny, что заодно отсекает честных игроков на Parallels и QEMU.
  • Linux слабее остальных. product_uuid и board_serial там читает только root, у лаунчера прав нет — отчёт помечается SMBIOS_UNREADABLE и держится на machine-id, дисках и ключе установки.
  • Аппаратный ключ Windows не проверялся на живом железе. Код ядра собирается и его тесты прогоняются на Windows и macOS в CI, но TPM на сборочных машинах нет, поэтому эта ветка остаётся непроверенной. Linux-путь — и сбор, и TPM — проверен на живой системе.
  • Вторая физическая машина непобедима, и это правильное конечное состояние: цель — чтобы обход стоил дороже, чем уйти в другой проект.

Честный пол: система надёжно останавливает гриферa, который заводит новый аккаунт; человека, удалившего ключ реестра по совету с форума; того, кто запустил взломанный сторонний лаунчер. Она не останавливает человека с деньгами и терпением — и ни одна клиентская система этого не делает.