Глава 7. Модель Безопасности
Модель безопасности Fayger опирается на две линии:
- Доверенное происхождение. Артефакт BuF может быть подписан; при загрузке проверяется источник и целостность.
- Контролируемое исполнение. BuF_Instance в рантайме может использовать только явно выданные capabilities; не объявленные capabilities полностью невидимы.
Линии «приземляются» соответственно в слое загрузки и слое адаптации, усиливаются моделью ошибок главы 6 и изоляцией сбоев главы 4.
7.1 Доверенное происхождение: подписи и дайджесты
Дайджесты
Каждая Section объявляет в BuF_Manifest свой digest. Фаза Verify Digest пересчитывает и сверяет на каждой Section:
- Любое несовпадение возвращает
LDR_DIGEST_MISMATCH. - Контекст содержит проваленный
section_id.
manifest_digest в Trailer одновременно проверяет, что сам Manifest не усечён и не модифицирован.
Область подписи
Покрываемые подписью байты:
Header || Manifest_minus_signature || Section_Index
Замысел:
- Даже если злоумышленник модифицирует любое поле Manifest после подписи (кроме блока подписи), подпись становится невалидной.
- Изменение offset / length / digest у Sections тоже инвалидирует подпись (Section_Index в области подписи).
- Тела Sections напрямую не покрыты, но их
digestесть в Manifest, поэтому покрытие косвенное.
Этот подход «подписать manifest, цепочка digest до sections» — тот же компромисс, что и у OCI Image: контролируемый размер входа подписи и предсказуемое время верификации.
Поддерживаемые алгоритмы подписи (фаза 1)
ed25519ecdsa-p256rsa-pss-sha256
Идентификатор алгоритма и ссылка на публичный ключ объявляются явно в блоке signature Manifest, без неявных согласований через ASN.1 / X.509.
Таблица решений по подписи
| Условие | Результат |
|---|---|
| enforce_signature on ∧ нет подписи | Err(LDR_SIGNATURE_FAIL), причина MissingSignature |
| подпись есть ∧ верификация не прошла | Err(LDR_SIGNATURE_FAIL), причина InvalidSignature |
| подпись есть ∧ верификация прошла | Ok |
| enforce_signature off ∧ нет подписи | Ok (удобство разработки) |
7.2 Режим обязательной подписи
Режим обязательной подписи (enforce signature) — переключатель политики загрузки, контролируемый LoaderPolicy.require_signature:
struct LoaderPolicy {
require_signature: bool
trusted_roots: TrustedRootSet
allowed_schema_versions: VersionRange
}
Поведение:
- Включён: любой BuF должен иметь подпись и пройти верификацию; иначе загрузка отклоняется.
- Выключен: BuF без подписи всё ещё загружается (удобство); BuF с невалидной подписью отклоняется («подделать подпись» нельзя).
Для release-сценариев (продакшн, доверенные каналы) рекомендуем по умолчанию задавать require_signature в true на уровне конфигурации.
7.3 Управление доверенными корнями
interface TrustStore {
current_roots() -> TrustedRootSet
update(roots: TrustedRootSet)
enforce_signature() -> bool
}
Ограничение видимости обновлений:
- Для последовательности
Opsсо смешаннымиUpdate(roots)иLoad(buf)каждая операцияLoad(buf)использует именно те корни, которые установил последний предшествующийUpdate. - Это делает семантически невозможной гонку «корни сменили посреди загрузки».
Стратегия реализации:
- На входе в каждый
LoaderPipeline.loadберётся снапшотTrustStore; вся загрузка использует снапшот. - Явно запрещено разделять изменяемое множество корней во время загрузки.
7.4 Контролируемое исполнение: capability-модель безопасности
Слой адаптации использует capability-based security (как WASI). BuF в Manifest объявляет запросы capabilities; Platform_Adapter и политика хоста совместно решают, что выдать.
Формально:
granted = requested ∩ available ∩ host_policy
denied = requested \ granted
Шлюз старта
Если manifest.required_capabilities \ granted ≠ ∅:
start()обязан вернуть ошибку.context.missingравен разности.- Инстанс не входит в Running.
Это жёсткое правило «не запускать при недостатке capabilities».
Запрет по умолчанию
- Не объявленные capabilities невидимы для BuF.
- Platform_Adapter не должен предоставлять не объявленные capabilities «потому что биты вроде совпадают».
- Неопознанные категории Universal_Instruction возвращают
ADP_UNSUPPORTED_INSTRUCTION; никаких «тихих проходов».
7.5 Классификация capabilities и заметки об усечении (по хосту)
| Класс хоста | Обычно доступно | Обычно недоступно | Примечание |
|---|---|---|---|
| Десктоп | io.*, net.*, ui.*, time, random, crypto, proc.*, host.* | зависит от платформы / прав | почти полный набор |
| Сервер | io.*, net.*, time, random, crypto, proc.* | ui.* отключён | без GUI по умолчанию |
| Браузер | net.fetch, net.websocket, ui.dom, time, random, подмножество crypto | proc.*, большая часть io.* | сильное усечение |
| In-App | явно инжектируется хостом | по умолчанию всё запрещено | самый строгий; финальное слово за хостом |
7.6 Изоляция ресурсов как барьер безопасности
Изоляция ресурсов — это и часть барьера безопасности:
- Сбой одного BuF_Instance не распространяется на другие (свойство изоляции из главы 4).
- Превышение квоты вызывает приостановку, не давая одному инстансу исчерпать ресурсы хоста.
- RuntimeDataAreas инстансов взаимно невидимы — это предотвращает утечки по сторонним каналам на уровне данных.
7.7 Взаимодействие безопасности и ошибок
Сбои, связанные с подписью и capabilities, возвращаются единой моделью:
- Сбой подписи:
LDR_SIGNATURE_FAIL, сMissingSignature/InvalidSignature. - Capability отказан:
ADP_CAPABILITY_DENIED, с отказанным набором. - Сбой шлюза старта: повторное использование
ADP_CAPABILITY_DENIED;context.missingнесёт разность.
Цепочки ошибок — как в главе 6: нижняя помещается в cause; верхняя помечает свой source_layer; вызывающие могут пройти по цепочке для локализации.
7.8 Рекомендации по аудиту
Аудит — не во внутреннем периметре Fayger, но шина событий, Lifecycle Events и Loader Events дают внешним аудит-системам достаточные якоря:
- События успеха / сбоя каждой фазы загрузки — как точки аудита источника.
- Lifecycle Events документируют тайм-линию старта / приостановки / завершения каждого инстанса.
- Результаты усечения — как точки аудита решений по безопасности.
- События сбоя подписи, отказа capability и превышения квоты могут подписываться внешним SIEM / аудит-конвейером.
