Я бы хотел создать систему плагинов со следующими функциями:
Во время поиска я в основном находил решения SO, связанные с безопасностью доступа кода, которые, насколько мне известно, устарели в .NET 4.x. Я также немного прочитал о новой модели безопасности на страницах MSDN, и, похоже, здесь понадобится код библиотеки, который предоставляет защищенные ресурсы; однако я не смог найти никаких примеров, показывающих, как применять такой код. Я предполагаю, что это потребует создания отдельных доменов приложений и, возможно, игры с разрешениями участника, но это примерно то, что мне известно.
Кстати, я также нашел упоминания о том, что требуются только сборки со строгими именами, но я не уверен, что этого будет достаточно. Если я не ошибаюсь, одним из сильных преимуществ именования является то, что разработчик плагина может подтвердить свою личность, подписав хэш сборки собственным закрытым ключом, а другие могут проверить, используя хорошо известный и надежный открытый ключ. Однако это само по себе кажется слишком негибким, поскольку требует либо от разработчика лично решать, чей код следует доверять, либо просто доверять любому, кто научился подписывать свою сборку.
Буду очень признателен за хороший пример кода управления безопасностью с использованием самой современной модели безопасности. Что я сейчас имею в виду:
Конечно, вы можете предложить альтернативную архитектуру, если она лучше достигает цели.
Должны ли плагины быть написаны на C# (или, скорее, есть ли какие-либо языковые ограничения для плагинов)?
В общем, я предполагаю, что сборки .NET, совместимые с версией .NET основного приложения, будут поддерживаться как плагины (написанные на C#, VB или другом языке компиляции .NET). У меня нет планов напрямую поддерживать другие библиотеки; если кто-то захочет подключить его, ему нужно будет создать для него интерфейс на основе .NET.
Хотя это не решает сути вашей проблемы, я думаю, что стоит изучить OIDC Hybrid Flow как средство для получения детального контроля над тем, какие плагины могут получить доступ к каким API. Вы можете применять области действия к соответствующим частям вашей поверхности API и назначать утверждения плагинам в зависимости от их уровня доступа. Какая бы сильная подпись или подобная инфраструктура вы в конечном итоге не использовали, она может обеспечить основу для аутентификации, в то время как утверждения и области действия затем обрабатывают особенности того, что именно разрешено делать плагину.
CAS не обесценивается, как заявлено @Evk. Я не думаю, что он когда-либо будет декектирован, поскольку сам .net framework активно его использует. Просто msft сейчас не рекомендует использовать его для песочницы. Тем не менее, я создал приложение, которое использует CAS для песочницы с такими же требованиями, как и ваше. Я знаю приложения, которые его используют. Например, у Bloomberg есть платформа под названием «AppPortal», которая использует CAS для создания песочницы. Я рад предоставить решение с CAS, если вы хотите его использовать.
Полагаю, какое-то дополнительное решение не повредит. Было бы неплохо получить какое-то объяснение, почему предлагаемое решение с использованием CAS обеспечивает лучшую песочницу, чем, скажем, простое создание AppDomain и установка его разрешений.
Что насчет того, чтобы запустить его как ограниченный пользователь, тогда у вас будет чрезвычайно ограниченный доступ как для вашей программы, так и для плагинов. Затем в вашем интерфейсе плагина вы добавляете функцию для локального и сетевого ввода-вывода. Затем, когда вы обращаетесь к ним, вы запускаете запрос от имени другого пользователя, используя олицетворение.





То, что вы спрашиваете, сложно на нескольких уровнях.
Ближе всего к этому я видел давно забытый проект 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-контейнера. Конечно, это большая задача, но в наши дни есть инструменты, чтобы это произошло.
Да, когда меня подтолкнули в сторону «контейнерной виртуальной машины», я немного поискал, и Docker был упомянут довольно заметно. Меня беспокоит одно: будет ли приложение работать сразу в Windows 7+ при условии, что установлена соответствующая версия .NET framework. Кажется, Docker не включен в Windows 7, хотя, может быть, есть способ как-то отправить его вместе с приложением ...?
Вы можете заставить плагины запускаться в отдельном процессе и взаимодействовать с вашим приложением только с помощью RPC. Таким образом, у них не будет доступа ни к чему, кроме того, что вы предоставили через API.
Операционная система Android делает то же самое, чтобы предоставить функциональные возможности для приложений Look IBinder.
Спасибо за ответ, я могу разобраться в этом в свободное время. Из того немногого, что я видел, кажется, что RPC предназначен для клиент-серверных приложений, и я предполагаю, что Application + API будет «серверным» уровнем, а Proxy + Plugin будет одним из «клиентов», верно? Тогда несколько вопросов: 1) Как мне настроить RPC-соединение в контексте логически единого приложения? 2) Могу ли я гарантировать, что приложение обращается к коду плагина синхронно (т.е. вызов из приложения в плагин и плагин, выполняющий свою логику, не прерывается)? 3) Каковы будут накладные расходы на такой вызов RPC?
@Alice 1) и 3) Вы можете запускать каждый плагин в отдельном процессе и использовать общую память для связи между процессами, что очень быстро. В ОС Windows вы можете использовать именованные каналы или написать свой собственный канал, как это сделал этот парень, и у него были примерно такие же требования youtube.com/watch?v=mLX1sYVf-Xg 2) Я не совсем понимаю этот вопрос, о каком прерывании вы говорите? можете ли вы предоставить более подробную информацию
Спасибо за видео, я собираюсь это проверить. Что касается 2), оглядываясь назад, я думаю, я имел в виду, что код запускается немедленно, а не непрерывно. Например, если я вызову локальный неасинхронный метод DoSomething (), его выполнение начнется немедленно. С другой стороны, если я вызываю метод DoSomething () на каком-либо сервере (WCF, HTTP, я не знаю), он ставит запрос в очередь перед его обработкой и передачей результата. Итак, я хотел бы знать, будет ли RPC, выполняемый основным приложением, порождающим несколько процессов, действовать «немедленно», как локальный метод, или в «очереди», как метод сервера.
@Alice Это зависит от вашей реализации транспортного уровня RPC, HTTP делает это, потому что он по умолчанию спроектирован таким образом. Если вы используете Pipes (связь через общую память между процессами), вы можете спроектировать метод для немедленного или асинхронного запуска.
Хорошо, спасибо большое. Еще один вопрос: как я могу запретить процессу плагина выполнять собственные конфиденциальные операции? Могу ли я создать для него ограничительный домен приложений или ...?
К сожалению, в Windows вы можете ограничить доступ только для каждого пользователя, а не для процесса приложения (плагина). так что, если этого достаточно, AppDomain выполнит свою работу.
Сам по себе CAS не является устаревшим, однако его использование в качестве границы безопасности между доверенным кодом (ваше приложение) и ненадежным (плагин) не рекомендуется. Насколько я понимаю, это потому, что MS не хочет его развивать и не будет исправлять какие-либо уязвимости, позволяющие обойти это. В них перечислены «альтернативные меры», которые вы можете использовать, если собираетесь выполнить неизвестный код, в разделе «Защита доступа к ресурсам» статьи, на которую вы ссылаетесь. В этом отношении не существует "замены" CAS (как упомянутой границе безопасности).