Плагин системной безопасности в .NET Framework 4.x (без CAS)

Я бы хотел создать систему плагинов со следующими функциями:

  • загрузка внешних плагинов из источников, которым я (разработчик) не доверяю, но которым доверяет конечный пользователь, установивший плагин
  • предоставление разрешений для каждого плагина в определенной области; например один плагин может иметь разрешение на чтение файлов из определенного местоположения, в то время как другим может быть разрешено подключаться к определенному местоположению веб-сайта
  • особый случай разрешений для каждого плагина: взаимодействует с другим объектом, скорее всего, предоставленным как экземпляр интерфейса, без доступа к каким-либо его непубличным членам (даже с помощью скрытых методов отражения)
  • предотвращение действий, с которыми конечный пользователь не согласился, таких как доступ к непубличным членам или работа с файловой системой, до того, как код плагина может причинить какой-либо вред

Во время поиска я в основном находил решения SO, связанные с безопасностью доступа кода, которые, насколько мне известно, устарели в .NET 4.x. Я также немного прочитал о новой модели безопасности на страницах MSDN, и, похоже, здесь понадобится код библиотеки, который предоставляет защищенные ресурсы; однако я не смог найти никаких примеров, показывающих, как применять такой код. Я предполагаю, что это потребует создания отдельных доменов приложений и, возможно, игры с разрешениями участника, но это примерно то, что мне известно.

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

Буду очень признателен за хороший пример кода управления безопасностью с использованием самой современной модели безопасности. Что я сейчас имею в виду:

  • интерфейс для обслуживания потенциально конфиденциальных операций (скажем, A и B)
  • фиктивная реализация сервиса, направленная на предотвращение несанкционированного выполнения этих операций
  • два плагина из отдельных сборок, один с разрешением на выполнение операции A, а другой с разрешением на операцию B
  • приложение, которое настраивает службу, загружает сборки с плагинами и пытается выполнять операции для каждого из них, так что неавторизованные операции блокируются, а авторизованные операции выполняются правильно
  • при запуске в приложении ни один плагин сам по себе не должен иметь доступ к общим чувствительным API, таким как файловый ввод-вывод или сеть, но это должно быть возможно сделать через службу.
  • все это при максимально возможном соблюдении эти рекомендации (в отличие от решений на основе CAS из вопросов SO из 2010 года)

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

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

Evk 29.03.2018 08:42

Должны ли плагины быть написаны на C# (или, скорее, есть ли какие-либо языковые ограничения для плагинов)?

ZiggZagg 31.03.2018 19:35

В общем, я предполагаю, что сборки .NET, совместимые с версией .NET основного приложения, будут поддерживаться как плагины (написанные на C#, VB или другом языке компиляции .NET). У меня нет планов напрямую поддерживать другие библиотеки; если кто-то захочет подключить его, ему нужно будет создать для него интерфейс на основе .NET.

Alice 31.03.2018 20:32

Хотя это не решает сути вашей проблемы, я думаю, что стоит изучить OIDC Hybrid Flow как средство для получения детального контроля над тем, какие плагины могут получить доступ к каким API. Вы можете применять области действия к соответствующим частям вашей поверхности API и назначать утверждения плагинам в зависимости от их уровня доступа. Какая бы сильная подпись или подобная инфраструктура вы в конечном итоге не использовали, она может обеспечить основу для аутентификации, в то время как утверждения и области действия затем обрабатывают особенности того, что именно разрешено делать плагину.

Fred Kleuver 01.04.2018 17:39

CAS не обесценивается, как заявлено @Evk. Я не думаю, что он когда-либо будет декектирован, поскольку сам .net framework активно его использует. Просто msft сейчас не рекомендует использовать его для песочницы. Тем не менее, я создал приложение, которое использует CAS для песочницы с такими же требованиями, как и ваше. Я знаю приложения, которые его используют. Например, у Bloomberg есть платформа под названием «AppPortal», которая использует CAS для создания песочницы. Я рад предоставить решение с CAS, если вы хотите его использовать.

Sriram Sakthivel 03.04.2018 21:30

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

Alice 04.04.2018 08:05

Что насчет того, чтобы запустить его как ограниченный пользователь, тогда у вас будет чрезвычайно ограниченный доступ как для вашей программы, так и для плагинов. Затем в вашем интерфейсе плагина вы добавляете функцию для локального и сетевого ввода-вывода. Затем, когда вы обращаетесь к ним, вы запускаете запрос от имени другого пользователя, используя олицетворение.

Archlight 04.04.2018 15:21
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
12
7
890
2

Ответы 2

То, что вы спрашиваете, сложно на нескольких уровнях.

Ближе всего к этому я видел давно забытый проект Microsoft под названием Террариум, в котором вы кодируете существо, используя язык .net, строите его и отправляете свою сборку, содержащую ваше существо, для жизни на террариумном сервере, который был написан на .NET. 1.0. Разработчикам MS было непросто создать среду, в которой любой пользователь может запускать код, но при этом быть безопасным и хорошо играть. Они создали инструмент, запрещающий использование определенных типов в сборке. Он называется AsmCheck.

Раньше я без особого успеха пытался добиться того же, используя домены приложений.

Время от времени я все еще думаю о том, как лучше всего решить эту задачу. Возможно, так работают Android и iOS, но для этого нужно, чтобы я написал всю ОС или фреймворк как можно лучше.

Я планировал создать AppDomain и загрузить в этот домен свой загрузчик плагинов. Затем загрузчик загружает сборку плагина и все сборки, которые он пытается загрузить, угоняя загрузчик сборок. При загрузке сборки он использует AsmCheck.vNext, чтобы проверить, не делает ли он что-то сомнительное. Для каждой загруженной сборки он использует контейнер IoC (например, это) для ограничения доступа к платформе.

Проверка сборок выполняется на моей стороне путем проверки строгих имен в моем реестре плагинов или проверки сертификатов для подписи кода.

Все кажется хорошим, пока вы не увидите Confuser или его преемника ConfuserEx. Он создает прокси-типы для доступа к методам путем преобразования метода в самоинициализирующиеся статические делегаты, которые ссылаются на методы не по имени, а по идентификатору ссылки. Теперь, как я могу проанализировать и / или ограничить доступ к этому.

Или вы можете полностью запретить пространство имен System.IO и предоставить вам собственную библиотеку ввода-вывода, но как вы можете ограничить использование PInvoke и вызова GetProcAddress, чтобы он мог получить доступ к ReadFile, WriteFile и т. д.

Слишком много дел, и это только верхушка айсберга. Если вам абсолютно необходимо ограничить плагины, чтобы делать что-то, вам нужно написать собственный фреймворк или предоставить язык сценариев, такой как lua.

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

Однажды я бы хотел увидеть, как кто-нибудь решит эту проблему простым и эффективным способом.

PS: Мой ответ не является ответом. Это ответ, потому что он просто не подходит для комментария.

Я думаю, что @edokan прав в том, что использование механизма «контейнерной виртуальной машины» - лучший способ на сегодняшний день. Вы можете разработать систему, которая запускает образы Docker, которые содержат подключаемые модули, и имеет уровень API для обмена данными между вашим основным приложением и подключаемым модулем Docker-контейнера. Конечно, это большая задача, но в наши дни есть инструменты, чтобы это произошло.

ajawad987 31.03.2018 05:11

Да, когда меня подтолкнули в сторону «контейнерной виртуальной машины», я немного поискал, и Docker был упомянут довольно заметно. Меня беспокоит одно: будет ли приложение работать сразу в Windows 7+ при условии, что установлена ​​соответствующая версия .NET framework. Кажется, Docker не включен в Windows 7, хотя, может быть, есть способ как-то отправить его вместе с приложением ...?

Alice 31.03.2018 12:20

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

Операционная система Android делает то же самое, чтобы предоставить функциональные возможности для приложений Look IBinder.

Спасибо за ответ, я могу разобраться в этом в свободное время. Из того немногого, что я видел, кажется, что RPC предназначен для клиент-серверных приложений, и я предполагаю, что Application + API будет «серверным» уровнем, а Proxy + Plugin будет одним из «клиентов», верно? Тогда несколько вопросов: 1) Как мне настроить RPC-соединение в контексте логически единого приложения? 2) Могу ли я гарантировать, что приложение обращается к коду плагина синхронно (т.е. вызов из приложения в плагин и плагин, выполняющий свою логику, не прерывается)? 3) Каковы будут накладные расходы на такой вызов RPC?

Alice 03.04.2018 08:31

@Alice 1) и 3) Вы можете запускать каждый плагин в отдельном процессе и использовать общую память для связи между процессами, что очень быстро. В ОС Windows вы можете использовать именованные каналы или написать свой собственный канал, как это сделал этот парень, и у него были примерно такие же требования youtube.com/watch?v=mLX1sYVf-Xg 2) Я не совсем понимаю этот вопрос, о каком прерывании вы говорите? можете ли вы предоставить более подробную информацию

Davit Tvildiani 03.04.2018 14:43

Спасибо за видео, я собираюсь это проверить. Что касается 2), оглядываясь назад, я думаю, я имел в виду, что код запускается немедленно, а не непрерывно. Например, если я вызову локальный неасинхронный метод DoSomething (), его выполнение начнется немедленно. С другой стороны, если я вызываю метод DoSomething () на каком-либо сервере (WCF, HTTP, я не знаю), он ставит запрос в очередь перед его обработкой и передачей результата. Итак, я хотел бы знать, будет ли RPC, выполняемый основным приложением, порождающим несколько процессов, действовать «немедленно», как локальный метод, или в «очереди», как метод сервера.

Alice 03.04.2018 20:10

@Alice Это зависит от вашей реализации транспортного уровня RPC, HTTP делает это, потому что он по умолчанию спроектирован таким образом. Если вы используете Pipes (связь через общую память между процессами), вы можете спроектировать метод для немедленного или асинхронного запуска.

Davit Tvildiani 03.04.2018 22:07

Хорошо, спасибо большое. Еще один вопрос: как я могу запретить процессу плагина выполнять собственные конфиденциальные операции? Могу ли я создать для него ограничительный домен приложений или ...?

Alice 04.04.2018 08:06

К сожалению, в Windows вы можете ограничить доступ только для каждого пользователя, а не для процесса приложения (плагина). так что, если этого достаточно, AppDomain выполнит свою работу.

Davit Tvildiani 05.04.2018 22:45

Другие вопросы по теме