Защита систем. Чему «Звездные войны» учат инженера ПО — страница 38 из 68


Таблица 6.2. Полномочия в облачной системе


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

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

Защита

Существует два типа важных защитных шаблонов. Одна группа – это то, что делает ваш код; другая – это контекст, в котором выполняется ваш код. Защита от атак расширения полномочий и повышения привилегий, по идее, проста. К сожалению, несмотря на эту простоту, на практике она часто оказывается замысловатой либо имеет множество нюансов.

Когда ваш код принимает входные данные от ненадежных сторон, он анализирует эти входные данные и реагирует на них различными способами. Если вы недостаточно осторожны, ваш код поможет злоумышленникам добиться своего.

Поэтому очень важно, чтобы вы случайно не создали синтаксический анализатор, представителя или систему разрешений. Продуманный дизайн и избегание технических неполадок быстро окупятся как с точки зрения безопасности, так и с точки зрения надежности, возможно, даже больше, чем любые другие инвестиции в безопасность. Беда в том, что эти вещи подкрадываются к вам незаметно, особенно синтаксический анализ. Если вы проснетесь и обнаружите, что случайно создали такую штуку, лучшим выходом будет взлететь и взорвать ее с орбиты. Затем все перестроить заново. Как бы трудно это ни было, со временем вы, вероятно, поймете, что это менее трудно, чем поддерживать ее. Тем не менее руководство часто мнется по различным деловым или психологическим причинам.

Эти деловые причины, наряду с общей сложностью построения правильного кода даже без этого рода проблем, означают, что инструменты изоляции и шаблоны проектирования невероятно полезны. (Это также то место, где может пригодиться «нулевое доверие».) Ниже перечислим эти инструменты.

• Разрешения и способности.

• «Песочницы».

• Контейнеры.

• Код без побочных эффектов, такой как функции Lambda. (Функция Lambda выполняет код, в то время как кто-то другой предоставляет серверную инфраструктуру, и Lambda не может изменять файлы на диске. Amazon позаимствовал этот термин из информатики; Google и Microsoft называют то же самое Functions, как в Azure Functions.)

• Системы типа «феникс», которые регулярно сносятся и восстанавливаются. (Это лишает злоумышленника текущего доступа, но, если вы заново отстроите точно такую же систему, тот же эксплойт будет работать, когда злоумышленник снова его использует.)

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

Наименьшие привилегии и разделение привилегий

«Оружие твое не нужно тебе», – говорит Йода Люку, когда тот входит туда, где сильна темная сторона силы. Йода выступает за принцип наименьших привилегий. Без оружия Люк с меньшей вероятностью причинит себе вред.

Злоумышленник, использующий уязвимость вашего кода, добавил его привилегии к своим. В сумме эти привилегии могут привести к тому, что он или сможет выполнять произвольный код, или же не сможет. Как только они позволят выполнять произвольный код, злоумышленник сможет достичь своих целей, или могут возникнуть дополнительные препятствия. Эти препятствия выставляются некоторой архитектурной особенностью. Если ваш код выполняется от имени администратора домена или root, то злоумышленник, скорее всего, сможет делать то, что захочет, без дополнительных препятствий, поскольку у него есть все привилегии. Это настолько контрпродуктивно, что в последних версиях macOS Apple неуклонно снижала власть учетной записи root, и к началу 2020-х годов root уже не могла изменять файлы ядра операционной системы.

Шаблон «root может все» непостижимо опасен. На самом деле, это не совсем так. Предоставление всех полномочий учетной записи (root, администратор домена) постижимо опасно. Профессионалы в области безопасности любят спорить о том, как трудно получить полномочия root из обычной учетной записи пользователя, и ответ на этот вопрос трудно поддается количественной оценке. Если вы с самого начала разрабатываете код для работы от имени обычного пользователя, вы получите множество преимуществ в плане безопасности и надежности и очень мало недостатков.

Мы можем противопоставить коду, имеющему все или большинство привилегий, противоположный шаблон: код, имеющий только те привилегии, которые необходимы для достижения конкретных целей. Выражения наименьшие привилегии и разделение привилегий (или обязанностей) широко распространены в сфере безопасности. Минимальные привилегии относятся к минимизации полномочий программы: проектирование ее работы с минимальными полномочиями. Разделение привилегий означает предоставление полномочий, необходимых системе, набору программ, разделенных значимыми способами, такими как запуск под разными идентификаторами пользователей Unix. (Возможно, вы заметили, что я заменил слово полномочия на слово привилегии; мы вернемся позже к тому, для чего я это сделал.) Разделение обязанностей относится к разделению обязанностей между людьми. Например, у менеджера банка есть ключи от сейфовой комнаты, а у меня есть ключ от сейфа. Аналогичным образом можно спроектировать систему, которая разделяет полномочия, предоставленные принципалам и, следовательно, программам.

Ограничение привилегий и «принцип наименьших привилегий» кажутся прекрасными идеями. Есть старая шутка: разница между теорией и практикой в том, что по теории никакой разницы нет. Первым шагом является обеспечение того, чтобы программы могли работать от имени «обычного пользователя», а не от имени администратора. Я хотел бы подчеркнуть, что первый шаг очевиден, но, если посмотреть вокруг, это эмпирически неверно.

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

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

Как написание кода для работы от имени обычного пользователя, так и ежедневное использование обычной учетной записи пользователя значительно повышает безопасность. На практике решить, достигли ли вы «наименьшего» результата, может быть непросто. Очень гибкие программы, такие как оболочка Windows, macOS Finder и веб-браузеры, бросают вызов принципу минимальных привилегий. В таких случаях системы «управления привилегиями», которые временно предоставляют расширенные полномочия, могут помочь реализовать принцип минимальных привилегий.

В более стесненных обстоятельствах реализации с наименьшими привилегиями могут поучиться у системы доставки почты qmail конца 1990-х годов, которая состоит из небольшого набора программ. Каждая программа запускается от имени отдельного пользователя Unix, и большинство программ имеют право читать из одного каталога и записывать в другой. (Это достигается сочетанием пользовательских и групповых разрешений.) Таким образом, семейство программ qmail спроектировано как единое целое с наименьшими полномочиями, которые им необходимы, и полномочия разделены между различными частями системы. На рисунке 6.3 показано, как это работает. Вам не нужно разбираться в деталях, чтобы продолжить, но вы можете видеть, что код выполняется с пятью идентификаторами пользователей (qmaild, qmailq, qmailr, qmails и root). Qmaild прослушивает порт 25, собирает почту и передает ее в систему очередей. Qmails отправляет его либо в удаленную систему (через qmailr), либо локальному пользователю. В случае с локальным пользователем qmail-lspawn, запущенный от имени root, создает пользовательский процесс для локальной доставки почты. Поскольку только этот процесс выполняется от имени root, он может быть подвергнут более тщательной проверке.


Рис. 6.3. Главные процессы qmail


Рисунок 6.3 взят из статьи об архитектуре безопасности qmail [Hafiz, 2004]. Если вы хотите узнать больше, это стóящий побочный квест. То, что qmail был вытеснен Postfix, не имело ничего общего с безопасностью.

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

Архитектура как барьер

Возможно, вам удастся упростить ваш синтаксический анализ, возможно, нет. Синтаксический анализ остается рискованным, и чем более уязвим код, тем разумнее этот код изолировать. Самые ранние шаблоны использовали для этого учетные записи и разрешения. Со временем демоны Unix перешли от запуска от имени root к запуску от имени их собственного идентификатора пользователя, и разрешения для этих учетных записей были ограничены. Современная версия этого проиллюстрирована предыдущим примером qmail. Запуск в качестве отдельного идентификатора пользователя – это форма изоляции, которая является важнейшей частью любой устойчивой стратегии защиты.