Object-capability модель: формальные гарантии вместо списков доступа

“Права доступа, это интерфейсы. Управление доступом, это композиция объектов. Вся безопасность, это следование инвариантам системы, которые можно доказать формально.”

От контрольных списков к объектам: что не так с традиционными моделями

Традиционные модели управления доступом, такие как Discretionary Access Control (DAC) или Mandatory Access Control (MAC), построены на идее централизованного контроля. Есть субъект (пользователь, процесс), есть объект (файл, сокет), есть политика — таблица или список правил, которые проверяются при каждом обращении. Проблема этого подхода — в его глобальности. Чтобы понять, может ли процесс A прочитать файл B, нужно анализировать всю систему прав, контекст вызова, наследование привилегий. Это сложно, а главное — непредсказуемо: маленькое изменение в одном месте может неочевидным образом открыть доступ в другом.

Object-capability model (OCM) предлагает инверсию этой логики. Здесь доступ, это не разрешение из списка, а свойство самого объекта-ссылки (capability). Если у тебя есть такая ссылка, ты можешь ею воспользоваться. Если нет — ни один центральный механизм не поможет её получить, кроме как от того, кто уже ей обладает. Права становятся первой гражданской ценностью системы, передаваемой, но не копируемой без ограничений.

Формальная семантика: что мы на самом деле доказываем

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

  • Инвариант изоляции: объект, не имеющий ссылки на другой объект, не может с ним взаимодействовать. Это не свойство проверки в runtime, а следствие архитектуры — ссылки физически отсутствуют в его пространстве.
  • Инвариант невозможности подделки: capability нельзя создать «из воздуха», без участия обладателя соответствующего права или доверенного фабриканта (seed). Это гарантируется на уровне языка или виртуальной машины.
  • Инвариант attenuation (ослабления): любое право можно обернуть в прокси-объект, который ограничивает исходный интерфейс. Новая ослабленная capability затем может быть передана дальше, не раскрывая исходный объект.

Формальные модели, такие как ACL2, Coq или Lean, позволяют описать эти инварианты на математическом уровне и доказать, что они выполняются при любом сценарии выполнения системы.

Компоненты модели: объекты, ссылки и сообщения

Вся система OCM описывается тремя простыми сущностями:

Сущность Роль Аналог в коде
Объект Инкапсулирует состояние и поведение. Единственный способ взаимодействия — отправка сообщения по имеющейся ссылке. Экземпляр класса (в E), актор (в Pony), компонент (в CloudABI).
Ссылка (capability) Неотъемлемое право на вызов определённого метода объекта. Ссылка, это и есть доступ. Указатель на объект + зашитый интерфейс. Не копируема без явного действия.
Сообщение Запрос к объекту, включающий данные и, возможно, передачу других ссылок. Вызов метода с аргументами.

Передача ссылки в сообщении — единственный способ распространить права в системе. Нет глобального пространства имён, нет рефлексии, которая могла бы получить доступ к объекту по строковому имени. Среда выполнения обеспечивает, что ссылка либо есть, либо её невозможно подделать.

Как это работает на практике: от языка до операционной системы

Реализация OCM возможна на разных уровнях стека. Каждый уровень даёт разные гарантии и требует разных усилий по верификации.

Языки программирования

Некоторые языки изначально спроектированы с учётом OCM. Например, язык E полностью построен на объектах-изолятах, которые обмениваются promises и capabilities. Ещё один пример — Pony с её моделью акторов и гарантиями отсутствия гонок данных (data race freedom). В таких языках компилятор и среда выполнения являются частью TCB (Trusted Computing Base) — они обеспечивают выполнение инвариантов.

// Упрощённый пример на псевдокоде, вдохновлённом E.
// Создаём объект-хранилище с единственной capability на запись.
let storage = makeSealedBox(initialData);
// Получаем две отдельные ссылки: одну только на чтение, другую — на запись.
let readCap = storage.getReadCapability();
let writeCap = storage.getWriteCapability();

// Мы можем передать readCap кому угодно, не опасаясь изменения данных.
giveToClient(readCap);
// writeCap остаётся у нас, клиент не может его получить.

Более распространённый подход — использование паттернов в существующих языках. В JavaScript-библиотеках (например, для Sandboxing) или в Go (через интерфейсы и внедрение зависимостей) создаются обёртки, которые эмулируют поведение capabilities. Однако без поддержки среды выполнения инвариант невозможности подделки держится только на дисциплине программиста.

Уровень операционной системы и гипервизора

Здесь OCM проявляется как принцип минимальных привилегий, доведённый до логического конца. CloudABI — пример runtime для C/C++, который полностью исключает глобальное пространство имён (нет файловых путей, сетевых адресов по строке). Вместо этого процесс запускается с набором file descriptors, которые и являются его capabilities на доступ к ресурсам. Новый дескриптор можно получить только от родительского процесса или через наследование из socket.

На уровне гипервизоров (например, в microkernel-based системах) компоненты взаимодействуют через IPC, передавая capabilities как handles. Без нужного handle сервис файловой системы просто физически не сможет получить доступ к блочному устройству.

Применение в регуляторике: 152-ФЗ и безопасность информации

Требования 152-ФЗ и документов ФСТЭК, такие как «Базовая модель угроз безопасности информации» или требования к СЗИ, часто формулируются в терминах контроля доступа, аудита и неизменности. OCM предлагает не просто механизм выполнения этих требований, а архитектурный подход, который делает нарушения невозможными по построению.

  • Минимизация привилегий: вместо учётных записей с широкими правами каждый компонент системы изначально обладает только теми capabilities, которые необходимы для его задачи. Это напрямую соотносится с принципом наименьших привилегий, обязательным при построении ЗИС.
  • Неизменность журналов аудита: в capability-системе сам факт передачи права является событием, которое можно логировать в неизменяемый объект-журнал. Поскольку создать capability обходным путём нельзя, журнал будет полным и достоверным.
  • Защита от несанкционированного доступа: угроза «несанкционированный доступ» в терминах OCM трансформируется. Если у злоумышленника нет capability на объект, он не может даже адресовать его в системе. Это сильнее, чем «запрос отклонён политикой».
  • Верификация СЗИ: формальная семантика OCM позволяет доказывать свойства системы защиты информации математически. Вместо тестирования на соответствие ТЗ можно доказать инварианты, например, что информация определённого класса не покинет периметр, составленный из определённых объектов.

Реализация в существующих российских экосистемах

Хотя чистые capability-системы редки, принципы проникают в отечественные разработки.

  • Виртуализация и контейнеризация: платформы виртуализации, используемые для изоляции контуров ЗИС, по сути, реализуют capability-модель на уровне гипервизора. Виртуальная машина получает «ссылку» на виртуальный диск, сетевой интерфейс, и не может выйти за их пределы.
  • Брокеры сообщений и service mesh: в микросервисных архитектурах, развёрнутых в госсекторе, sidecar-прокси (как в Istio) действуют как attenuating proxy. Они получают capability на вызов удалённого сервиса, добавляют аутентификацию, аудит и логирование, и только затем передают ослабленное право внутреннему сервису.
  • Специализированные ОС: разработки на базе микроядер (аналоги QNX, SEL4) потенциально могут использовать OCM для построения высокоассиured систем. Формальная верификация микроядра даёт основу для доказательства безопасности всей композиции.

Ограничения и сложности внедрения

OCM — не серебряная пуля. Её adoption сталкивается с серьёзными препятствиями.

  • Ментальный сдвиг: программистам приходится отказываться от глобального состояния, синглтонов и прямой файловой работы в пользу явной передачи всех ресурсов через зависимости.
  • Экосистема: большинство библиотек и фреймворков не рассчитаны на capability-стиль. Интеграция со legacy-системами требует создания шлюзов (gateways), которые сами становятся объектами доверия.
  • Производительность: проверка прав на уровне передачи сообщений может быть накладной, если не поддержана аппаратно или на уровне языка.
  • Управление жизненным циклом: в системе без глобальных ссылок сборка мусора и управление зависимостями усложняются. Нужны механизмы для безопасного revoking (отзыва) capabilities.

Несмотря на это, подход OCM остаётся наиболее чистым с теоретической точки зрения способом построения безопасных систем. Его понимание необходимо не для немедленного внедрения, а для корректной оценки рисков и возможностей современных архитектур, которые всё чаще заимствуют его отдельные принципы.

Оставьте комментарий