LaPorta USB

Справочник: файл политики

Политика — один файл JSON. Путь к нему задаётся при установке параметром POLICYPATH и хранится в реестре; его читают и служба, и окно администратора. Имена полей — в нижнем регистре через подчёркивание (enforcement_mode, strict_mode).

Разбор снисходителен к трём вещам: незнакомые поля пропускаются (по ним новая версия программы не ломает старую политику), комментарии // разрешены, запятая после последнего элемента списка ошибкой не считается.

Целый пример

{
  "version": 7,
  "updated_utc": "2026-08-18T09:14:00Z",
  "updated_by": "DOMAIN\\petrov",
  "enforcement_mode": "audit",
  "strict_mode": false,
  "notify_user": true,
  "defaults": { "flash": "block", "external_hdd": "block", "other": "allow" },
  "rules": [
    { "id": "R-001", "match": { "serial": "001cc0ec34d5" }, "action": "allow",
      "note": "Флешка бухгалтерии №1", "owner": "Иванова А.П." },
    { "id": "R-014", "match": { "vid": "0951", "pid": "1666" }, "action": "readonly" }
  ],
  "log": { "retention_days": 90, "share_path": "\\\\server\\laportausb$\\logs" }
}

Поля верхнего уровня

ПолеОбязательноЗначение
versionдаЦелое больше нуля. По нему окно администратора замечает, что файл правил кто-то ещё
updated_utcнетВремя последней правки
updated_byнетКто правил
enforcement_modeнетaudit либо enforce. Без поля — audit
strict_modeнетПревентивный слой. Без поля — выключен
notify_userнетУведомления в трее. Без поля — включены
defaultsдаДействие по классу носителя
rulesнетПравила по отдельным устройствам
logнетСрок хранения журнала и путь выгрузки

Поле strict_mode включает превентивный слой — запрет установки неизвестных USB-накопителей через ветку ограничений установки устройств, а не только отключение уже подключённых. Действует лишь вместе с enforcement_mode: enforce: в паре с audit strict_mode ничего не включает, режим наблюдения ничего не ограничивает. Устройство слоя, порядок регистрации носителя в белом списке и срок жизни этого списка — в overview.md.

Незнакомое значение enforcement_mode — ошибка разбора, а не молчаливое возвращение к audit. Иначе опечатка в слове enforce оставила бы машину в режиме наблюдения, а администратор считал бы, что запреты включены.

Умолчания по классам устройств

"defaults": { "flash": "block", "external_hdd": "block", "other": "allow" }
КлючОбязателенПримечание
flashдаФлешка
external_hddдаВнешний диск
otherнетПрочие USB-устройства. Без ключа — allow
tokenзапрещёнВалидатор отвечает: «Класс token не настраивается политикой: токены никогда не блокируются»
unknownнет такого ключаКласс не определён — решение по устройству не пересчитывается

Класс unknown означает, что узел устройства отключён и не запущен: система сообщает идентификатор, VID/PID и имя, но не сменность носителя, а без неё флешку от внешнего диска не отличить. Догадка стоила бы неверного решения, поэтому класс остаётся неопределённым.

Правила

Правило — отбор устройства (match) и действие над ним (action).

ПолеОбязательноЗначение
idдаНеповторяющийся в пределах файла
matchдаУсловие отбора, см. ниже
actionдаallow, readonly либо block
noteнетДля человека: что это за носитель
ownerнетДля человека: чей он
added_utcнетКогда правило заведено

Внутри match:

ПолеЗначение
serialСерийный номер устройства
vidИдентификатор изготовителя, ровно четыре шестнадцатеричные цифры
pidИдентификатор изделия, ровно четыре шестнадцатеричные цифры
interfacesСостав интерфейсов, записи вида класс:подкласс:протокол
interfaces_matchequals либо none_of. Без поля — equals

Задаётся либо serial, либо пара vid+pid целиком. Одно с другим одновременно — ошибка; половина пары — тоже ошибка. serial, vid и pid приводятся к верхнему регистру, так что регистр в файле значения не имеет.

Записи в interfaces — шестнадцатеричные пары, звёздочка допускается вместо целой доли: 03:*:* — любая клавиатура или мышь, 08:06:50 — обычный накопитель. equals требует совпадения состава, none_of — отсутствия перечисленного. Устройство, состав интерфейсов которого прочитать не удалось, не удовлетворяет никакому условию: разрешать по неподтверждённому значит открывать ровно ту дверь, ради закрытия которой условие и заводилось.

Пример правила с условием — разрешить этот накопитель, пока он остаётся только накопителем:

{
  "version": 12,
  "enforcement_mode": "enforce",
  "defaults": { "flash": "block", "external_hdd": "block" },
  "rules": [
    { "id": "R-021",
      "match": { "serial": "001CC0EC34D5", "interfaces": ["03:*:*"], "interfaces_match": "none_of" },
      "action": "allow", "note": "Отзывается, если внутри окажется клавиатура" }
  ]
}

Порядок применения правил

Решение принимается первым подошедшим пунктом сверху вниз. В журнал попадает причина — она в скобках.

  1. Токен (token_never_enforced). Всегда allow. Ни одно правило к токену не применяется: заблокированный токен — это потерянный вход в систему.
  2. Точное правило по serial (exact_rule_serial). Только если серийный номер заслуживает доверия: часть дешёвых носителей сообщает один номер на всю партию.
  3. Групповое правило по vid+pid (group_rule_vid_pid). Правило с заданным serial на этом шаге не рассматривается.
  4. Умолчание по классу (default_flash, default_external_hdd, default_other).

Из нескольких правил, подошедших на одном шаге, выигрывает block; если запрета среди них нет — первое по порядку в файле.

Условие interfaces уточняет правило, а не образует своё. Не совпало — правило не применяется вовсе, и устройство уходит дальше по списку, к умолчанию. Так не возникает вопроса о старшинстве между правилом по серийнику и правилом по составу.

Если класса нет в умолчаниях, решение — block: молча разрешить неизвестный класс опаснее, чем запретить. При действительной политике эта ветка недостижима, потому что flash и external_hdd обязательны.

Журнал

"log": { "retention_days": 90, "share_path": "\\\\server\\laportausb$\\logs" }

retention_days — файлы журнала старше этого срока удаляются. Значение должно быть больше нуля. Без раздела log действует 90 дней.

share_path — каталог, куда выгружается копия журнала. Пусто или поля нет — выгрузка не выполняется.

Ошибки разбора

Политика, которая не разобралась, не применяется. Служба продолжает работать по последней удачно прочитанной политике из кэша, а если и кэша нет — уходит в запасной режим и разрешает всё. Молчаливого частичного применения не бывает: либо файл разобран целиком, либо не принят целиком.

Отказы выглядят так:

Поле version обязательно и должно быть больше нуля
Класс token не настраивается политикой: токены никогда не блокируются
Правило R-007: serial и vid/pid нельзя задавать одновременно
Неизвестное действие 'deny'. Допустимы: allow, readonly, block

Проверить файл до раскатки можно в окне администратора, на вкладке политики: оно разбирает файл тем же кодом, что и служба, и показывает те же строки.