Когда два разных человека работают за одним компьютером под разными учётными записями, один из них не может открыть личные документы другого, даже если оба находятся на одном диске в соседних папках. Это ощущается как нечто само собой разумеющееся, но за этой простой картиной стоит отдельная подсистема операционной системы, которая при каждом обращении к файлу, разделу реестра, принтеру или процессу заново решает один и тот же вопрос: разрешено ли именно этому пользователю то действие, которое он пытается выполнить. Ответ на этот вопрос система находит не по имени владельца и не по паролю, а по паре куда менее очевидных объектов - дескриптору безопасности, прикреплённому к файлу, и маркеру доступа, который несёт с собой каждый процесс пользователя.
Что находится внутри дескриптора безопасности объекта
Любой защищаемый объект Windows, будь то файл на диске NTFS, раздел реестра, именованный канал, принтер или объект ядра вроде процесса, обладает собственным дескриптором безопасности. Структурно он описывается типом SECURITY_DESCRIPTOR и включает четыре основных компонента: идентификатор безопасности владельца объекта, необязательный идентификатор безопасности основной группы, дискреционный список контроля доступа и системный список контроля доступа. Первый компонент отвечает на вопрос, кто считается владельцем файла и, соответственно, имеет право в любой момент изменить правила доступа к нему. Третий и четвёртый компоненты - это, по сути, два разных списка правил: один описывает, кому разрешено или запрещено обращаться к объекту, а второй определяет, какие попытки доступа нужно фиксировать в журнале аудита.
Дескриптор создаётся в момент появления объекта и обычно передаётся функции создания в виде указателя на структуру атрибутов безопасности. Если приложение не указывает собственный дескриптор явно, система подставляет значение по умолчанию, взятое из маркера доступа процесса-создателя, поэтому у нового файла почти всегда оказывается владелец и базовый набор разрешений, даже если программист не задумывался об этом специально.
SID как постоянный и неизменяемый идентификатор пользователя
Внутри дескриптора безопасности владелец объекта обозначен не именем учётной записи, а идентификатором безопасности - SID. Это уникальная числовая последовательность вида S-1-5-21 с несколькими группами цифр после дефиса, которая присваивается пользователю, группе или другому субъекту безопасности один раз при создании учётной записи и остаётся неизменной на протяжении всего её существования в пределах домена или локальной системы. Такое устройство решает практическую проблему: имя пользователя можно сменить, но SID при этом останется прежним, и все объекты, у которых в дескрипторе безопасности записан именно этот идентификатор, продолжат корректно распознавать владельца даже после переименования учётной записи.
Помимо уникальных SID, привязанных к конкретным пользователям и группам, в системе существуют так называемые известные идентификаторы - постоянные значения, одинаковые на любом компьютере с Windows, которые обозначают встроенные группы вроде всех пользователей системы или локальных администраторов. Именно на такие известные SID часто опираются правила доступа по умолчанию, которые Windows устанавливает для новых файлов и папок.
Списки ACE в DACL решают, кому и что разрешено с файлом
Дискреционный список контроля доступа, или DACL, - это упорядоченный набор записей, каждая из которых называется ACE, элемент управления доступом. Одна запись ACE связывает конкретный SID с набором прав и указанием, разрешает эта запись доступ или, наоборот, запрещает его. Логика проверки построена так, что запрещающие записи в списке всегда обрабатываются раньше разрешающих, поэтому явный запрет на конкретного пользователя или группу нельзя обойти, добавив ниже по списку более общее разрешение.
Права, которые может описывать одна запись ACE, довольно разнообразны и зависят от типа объекта. Для файла и папки на практике важны такие категории:
- чтение содержимого и базовых атрибутов объекта - без этого права приложение не сможет даже открыть файл для просмотра;
- запись новых данных и изменение существующего содержимого - право, которое отделяет читателя документа от его редактора;
- изменение самого дискреционного списка контроля доступа - право WRITE_DAC, позволяющее менять, кому ещё разрешён доступ к объекту;
- смена владельца объекта - право WRITE_OWNER, которое обычно закреплено только за самим владельцем и за администраторами системы.
Владелец объекта всегда сохраняет неотъемлемую возможность изменить его DACL, даже если по ошибке или намеренно лишил себя всех остальных прав на этот объект. Это встроенное свойство системы защищает от ситуации, когда файл случайно становится недоступным навсегда даже для собственного владельца.
SACL фиксирует попытки доступа для журнала аудита
Второй список, SACL, устроен структурно так же, как DACL, но служит другой цели: он не разрешает и не запрещает доступ, а определяет, какие операции с объектом и от имени каких пользователей должны попадать в журнал аудита безопасности. Администратор системы может настроить SACL так, чтобы фиксировались только неудачные попытки открыть защищённый файл, только успешные, или оба типа событий сразу. На практике SACL особенно востребован в корпоративной среде, где требуется доказуемо отслеживать обращения к чувствительным документам, разделам реестра или объектам домена, а не просто ограничивать доступ к ним.
Важная особенность SACL в том, что его чтение и изменение само по себе является привилегированной операцией. Обычного права на просмотр содержимого файла недостаточно, чтобы увидеть его политику аудита - для этого нужны отдельные права ACCESS_SYSTEM_SECURITY, которые по умолчанию есть далеко не у каждого пользователя.
Маркер доступа и как система сравнивает его с DACL объекта
Дескриптор безопасности описывает объект, но для проверки прав системе нужна вторая сторона - сведения о том, кем является пользователь, пытающийся получить доступ. Эту роль играет маркер доступа, access token. Он создаётся службой входа в систему сразу после успешной проверки подлинности и содержит SID учётной записи пользователя, SID всех групп, в которые он входит, идентификатор конкретного сеанса входа и список привилегий, которыми пользователь обладает в системе в целом. Копия этого маркера прикрепляется к каждому процессу и потоку, запущенному от имени пользователя, и именно она сопровождает любую попытку обратиться к защищаемому объекту.
За само сравнение маркера доступа с дескриптором безопасности объекта отвечает компонент ядра, который называется монитором ссылок безопасности, Security Reference Monitor. При попытке открыть файл он последовательно проходит по записям ACE в DACL объекта и ищет среди них такие, чей SID совпадает с одним из SID в маркере доступа запрашивающего процесса. Как только находится подходящая запись, применяются именно её права: если это запрет, доступ немедленно отклоняется, если разрешение - процессу выдаются запрошенные права в пределах того, что позволяет эта запись. Если ни одна запись ACE в списке не упомянула ни один из SID пользователя, результат по умолчанию - отказ в доступе, а не молчаливое разрешение.
Такая же логика распространяется и на процессы. Каждый маркер доступа не статичен: с помощью специальных функций систему можно попросить создать ограниченную копию маркера, из которой удалены отдельные привилегии или добавлены дополнительные запрещающие идентификаторы, применяемые при запуске недоверенного кода. В этом случае Security Reference Monitor проводит уже не одну, а две последовательные проверки доступа - одну по обычному набору SID из маркера и вторую по списку ограничивающих идентификаторов, и доступ предоставляется лишь тогда, когда обе проверки по отдельности подтверждают разрешение. Этот механизм часто используют службы и песочницы, которым разработчик хочет оставить формальную видимость привилегий пользователя, но фактически лишить их возможности трогать большинство объектов файловой системы.
Как NTFS хранит дескрипторы безопасности на диске
Файловая система NTFS устроена так, что каждый файл и каждая папка на томе действительно обладает собственным дескриптором безопасности, но физически на диске эти данные хранятся экономно. NTFS сохраняет только одну копию каждого уникального дескриптора безопасности, даже если один и тот же набор правил доступа применён сразу к тысячам файлов, а не дублирует идентичные структуры для каждого объекта по отдельности. На практике это означает, что после установки типовых разрешений на целую папку с вложенными файлами система хранит единственное представление этого дескриптора и лишь ссылается на него из записей отдельных файлов в главной таблице файлов, что заметно экономит место и ускоряет операции с правами доступа при работе с большими деревьями каталогов.
Как увидеть дескриптор безопасности своими глазами
В обычном режиме работы с проводником Windows человек видит лишь верхний слой этой системы - вкладку свойств файла со списком пользователей и групп и отмеченными галочками разрешений. За этим интерфейсом стоит текстовое представление дескриптора безопасности, которое можно получить и без графической оболочки. Язык описания дескрипторов, SDDL, превращает всю структуру в единую строку с четырьмя разделами: O для владельца, G для основной группы, D для DACL и S для SACL, где каждая отдельная запись ACE заключена в круглые скобки и содержит тип записи, флаги наследования, маску прав и SID. Такая строка неудобна для чтения человеком, но зато однозначна для программ и легко передаётся между системами при экспорте и импорте политик безопасности.
На практике увидеть владельца и список разрешений конкретного файла можно через встроенные средства командной строки, например утилитой icacls, которая построчно выводит SID или имя каждого субъекта из DACL вместе с сокращённым обозначением выданных ему прав. В оболочке PowerShell для той же цели существует командлет Get-Acl, возвращающий объект с владельцем, группой и списком правил доступа, который затем можно программно анализировать, сравнивать между файлами или переносить с одного объекта на другой. Наиболее часто встречающиеся в реальных дескрипторах известные SID имеют фиксированные значения независимо от компьютера и языка системы: например, идентификатор с суффиксом 500 в цепочке цифр домена традиционно закреплён за встроенной учётной записью администратора, а специальные идентификаторы вроде того, что обозначает всех прошедших проверку подлинности пользователей, встречаются в дескрипторах системных папок практически на любой установке Windows.
Что происходит при смене владельца и наследовании прав
Когда файл создаётся внутри папки с уже настроенными правами доступа, он по умолчанию наследует записи ACE от родительского объекта, если только создающее приложение не указало иной дескриптор безопасности явно. Это позволяет администратору один раз настроить права на верхнеуровневую папку и быть уверенным, что новые файлы внутри неё унаследуют ту же политику доступа без ручной настройки каждого отдельного объекта. При этом наследование можно отключить для конкретного объекта, установив флаг, который защищает его список DACL от автоматического распространения родительских правил.
Смена владельца объекта - отдельная и более чувствительная операция. Право WRITE_OWNER позволяет передать владение объектом другому SID, но на практике эта возможность жёстко ограничена: обычно её могут выполнить только сам текущий владелец, пользователи с соответствующей системной привилегией или локальные администраторы. Такое ограничение существует не случайно - если бы любой пользователь с правом записи мог свободно назначать себя владельцем чужих файлов, вся модель дискреционного контроля доступа потеряла бы смысл, поскольку владение объектом фактически даёт неограниченную власть над его дальнейшей судьбой независимо от того, что записано в текущем DACL.