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

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

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

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

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

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

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

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

Ответ 1

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

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

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

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

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

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

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

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

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

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

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

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

Ответ 2

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

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

enter image description here