Всем здравия!
Есть задача в приложении исполнять пользовательский код (что-то типа плагинов), реализующий разные хотелки бизнес-логики.
Хочется для написания кода использовать C# и компилять код в сборку. Но требуется обеспечить безопасность, чтоб не могли делать сис вызовы в ОС, не могли лезть в файловую систему.
Есть вариант — поднимать рядом подпроцесс (возможно в контейнере), тогда всё получается, но для скорости хотелось бы инпроц (чтоб напрямую получать ссылки на объекты хост-приложения и тп).
Вообщем с вариантом 1 всё ясно, хотелось бы подумать/понять есть ли возможность обеспечить безопасность в случае инпроц исполнения этих плагинов (скомпиленного юзер-кода).
Ранее в .Net FW были домены, и там была возможность ограничить доступ к локальной файловой системы (и прочие возможности), но в коре их выпилили и не хотелось бы сейчас строить на их базе.
Поэтому остаётся вариант только предварительного анализа кода анализаторами, на предмет остуствия использования запрещённого.
С 1-го взгляда вроде задача решаемая, для этого — запретить создание/доступы к классам в определённых нэймспейсах, запретить рефлексию, запретить активаторы (чтоб по типу нельзя создать объект), запретить
использование dllimport. возможно что-то упустил, но вроде есть ощущение что задача конечная и решаемая...
Хотелось бы понять, если в этом направлении пойти, задача решаемая? кто что думает?
Здравствуйте, MadHuman, Вы писали:
MH>Вообщем с вариантом 1 всё ясно, хотелось бы подумать/понять есть ли возможность обеспечить безопасность в случае инпроц исполнения этих плагинов (скомпиленного юзер-кода). MH>Ранее в .Net FW были домены, и там была возможность ограничить доступ к локальной файловой системы (и прочие возможности), но в коре их выпилили и не хотелось бы сейчас строить на их базе. MH>Поэтому остаётся вариант только предварительного анализа кода анализаторами, на предмет остуствия использования запрещённого. MH>С 1-го взгляда вроде задача решаемая, для этого — запретить создание/доступы к классам в определённых нэймспейсах, запретить рефлексию, запретить активаторы (чтоб по типу нельзя создать объект), запретить MH>использование dllimport. возможно что-то упустил, но вроде есть ощущение что задача конечная и решаемая... https://stackoverflow.com/questions/58468896/sandboxing-in-net-core MH>Хотелось бы понять, если в этом направлении пойти, задача решаемая? кто что думает?
Две разных задачи, разные пути решения:
1. Изоляция сбоев. (Предположим, запускаемый код решил выполнить while(true);). Тут, как я понял, вариантов нет — отдельный процесс и всё.
2. Безопасность.
Тут, как я понял, варианты есть, но готовые мне неизвестны. Можно пойти разными путями:
1. Принимать код в виде исходников, парсить его при помощи Roslyn и анализировать AST
2. Принимать код в виде сборки, и анализировать MSIL.
В обоих подходах ищем небезопасные конструкции, и в случае чего делаем панику.
Детали зависят от того, что вы хотите разрешать делать.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>https://stackoverflow.com/questions/58468896/sandboxing-in-net-core
спасибо. почитал, предлагается в отдельном процессе делать. как раз хотелось бы избежать этого.
основная причина для избежания такого варианта — ожидается очень интенсивное взаимодействие с хостом и его данными (уже готовыми и лежащими в памяти).
MH>>Хотелось бы понять, если в этом направлении пойти, задача решаемая? кто что думает? S>Две разных задачи, разные пути решения: S>1. Изоляция сбоев. (Предположим, запускаемый код решил выполнить while(true);). Тут, как я понял, вариантов нет — отдельный процесс и всё.
это неприятно (зацикливание), но не настолько опасно как доступ к файлам и функциям ОС.
в плохом варианте (когда зациклят), снизится перфоманс сервера, неприятно но не смертельно. процесс можно пристрелить, рестартовать.
вычислить какой плагин это делает и заблочить его.
S>2. Безопасность. S>Тут, как я понял, варианты есть, но готовые мне неизвестны. Можно пойти разными путями: S>1. Принимать код в виде исходников, парсить его при помощи Roslyn и анализировать AST
да, такой вариант и хочу, но нет уверенности что можно выявить / отследить все варианты опасного доступа.
пока рабочий вариант того что запретить:
— запретить вызовы по рефлексии.
— запретить создание инстансов через активатор.
— запретить dynamic
— запретить доступ к опасным классам (создание по new и вызов статических методов), типа File, Path, Directoty и тп
— запретить декларацию dllimport и тем самым нативные вызовы к ОС.
но не уверен, что этого достаточно.
если реализовать эти запреты, остаются ли варианты как их как-то обойти и всё таки создать/вызвать запрещённые объекты/методы?
вроде выглядит что достаточно, но почему тогда не гуглится что таким образом кто-то пытался реализовать ограничения? ненагуглил или есть фундаментальная проблема?
Здравствуйте, MadHuman, Вы писали:
S>>https://stackoverflow.com/questions/58468896/sandboxing-in-net-core MH>спасибо. почитал, предлагается в отдельном процессе делать. как раз хотелось бы избежать этого. MH>основная причина для избежания такого варианта — ожидается очень интенсивное взаимодействие с хостом и его данными (уже готовыми и лежащими в памяти).
Ну придется на MemoryMappedFiles что-то изобразить своё, решаемо.
S>>2. Безопасность. S>>Тут, как я понял, варианты есть, но готовые мне неизвестны. Можно пойти разными путями: S>>1. Принимать код в виде исходников, парсить его при помощи Roslyn и анализировать AST MH>да, такой вариант и хочу, но нет уверенности что можно выявить / отследить все варианты опасного доступа.
MH>но не уверен, что этого достаточно. MH>если реализовать эти запреты, остаются ли варианты как их как-то обойти и всё таки создать/вызвать запрещённые объекты/методы?
Мне кажется, потенциально опасное решение. Можно что-то забыть и получить свой log4j.
Раз у тебя отдельный процесс, пусть он будет с SIDом бесправного пользователя и работают встроенные механизмы безопасности.
Здравствуйте, MadHuman, Вы писали:
MH>в приложении исполнять пользовательский код (что-то типа плагинов) MH>Но требуется обеспечить безопасность, чтоб не могли делать сис вызовы в ОС, не могли лезть в файловую систему
По-моему, это параноидальный перебор (с т.з. решения "хост-плагины"). По-идее, плагин — это тоже ЧАСТЬ ХОСТА, просто динамически загружаемая. Что умеет хост — то умеет плагин. А если это некие "недоверенные чёрные ящики", так им по-любому место в отдельных "бесправных" процессах + ваш хост, торчащий наружу микросервисами + RPC.
А что вообще за задача? А то опять мы решаем "авторское решение", которое он любезно предоставил из собственных мыслей! Может, там и плагинов-то никаких не надо — тупо запилить DSL и вот тебе полная секурность.
Здравствуйте, MadHuman, Вы писали: S>>1. Изоляция сбоев. (Предположим, запускаемый код решил выполнить while(true);). Тут, как я понял, вариантов нет — отдельный процесс и всё. MH>это неприятно (зацикливание), но не настолько опасно как доступ к файлам и функциям ОС. MH>в плохом варианте (когда зациклят), снизится перфоманс сервера, неприятно но не смертельно. процесс можно пристрелить, рестартовать. MH>вычислить какой плагин это делает и заблочить его.
Тут как раз проблема — в том, что прибивать придётся весь процесс, в котором не только плагин, но и основная логика.
Для того, чтобы прибивание процесса не повредило инварианты, придётся какие-то отдельные приседания делать. Иначе нарвётесь на что-нибудь типа того, что процесс выполнил какую-нибудь файловую операцию, позвал плагин — и завис. И в зависимости от того, насколько быстро watchdog пристрелит процесс, файловая операция может как доехать, так и не доехать до диска.
В итоге с какой-то вероятностью ваше приложение будет портить свои данные.
MH>пока рабочий вариант того что запретить: MH>- запретить вызовы по рефлексии. MH>- запретить создание инстансов через активатор. MH>- запретить dynamic MH>- запретить доступ к опасным классам (создание по new и вызов статических методов), типа File, Path, Directoty и тп MH>- запретить декларацию dllimport и тем самым нативные вызовы к ОС.
MH>но не уверен, что этого достаточно. MH>если реализовать эти запреты, остаются ли варианты как их как-то обойти и всё таки создать/вызвать запрещённые объекты/методы?
Если честно — то риск есть всегда. В основном — в виде всяческих транзитивностей. Например, вызов каких-нибудь десериализаторов: в "пользовательском" коде вызовов рефлексии нету, а вот в коде, который он импортирует — есть.
И так далее. MH>вроде выглядит что достаточно, но почему тогда не гуглится что таким образом кто-то пытался реализовать ограничения? ненагуглил или есть фундаментальная проблема?
По соседству уже посоветовали начать от обратного: выяснить, что эти плагины должны делать, и попробовать прикрутить DSL (возможно, на основе чего-то готового вроде того же шарпа), в котором опасных конструкций просто нет совсем.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Тут как раз проблема — в том, что прибивать придётся весь процесс, в котором не только плагин, но и основная логика. S>Для того, чтобы прибивание процесса не повредило инварианты, придётся какие-то отдельные приседания делать. Иначе нарвётесь на что-нибудь типа того, что процесс выполнил какую-нибудь файловую операцию, позвал плагин — и завис. И в зависимости от того, насколько быстро watchdog пристрелит процесс, файловая операция может как доехать, так и не доехать до диска. S>В итоге с какой-то вероятностью ваше приложение будет портить свои данные.
может быть и так. а может и нет. если воркер процесс делается стэйт-лесс, то такого не происходит. вообщем риск понятен, как обходить/избегать понятно.
более того, риск падения основного процесса часто и так присутсвует, так что проектровать и его стоит так чтоб минимизировать и избегать подобных последствий.
MH>>пока рабочий вариант того что запретить: MH>>- запретить вызовы по рефлексии. MH>>- запретить создание инстансов через активатор. MH>>- запретить dynamic MH>>- запретить доступ к опасным классам (создание по new и вызов статических методов), типа File, Path, Directoty и тп MH>>- запретить декларацию dllimport и тем самым нативные вызовы к ОС.
MH>>но не уверен, что этого достаточно. MH>>если реализовать эти запреты, остаются ли варианты как их как-то обойти и всё таки создать/вызвать запрещённые объекты/методы? S>Если честно — то риск есть всегда. В основном — в виде всяческих транзитивностей. Например, вызов каких-нибудь десериализаторов: в "пользовательском" коде вызовов рефлексии нету, а вот в коде, который он импортирует — есть.
он импортирует строго ограниченное подмножество.
S>По соседству уже посоветовали начать от обратного: выяснить, что эти плагины должны делать, и попробовать прикрутить DSL (возможно, на основе чего-то готового вроде того же шарпа), в котором опасных конструкций просто нет совсем.
там советует известный местный токсик, с которым вести дискуссии неплодотворно. но этот путь уже пройден, те варианты для которых можно было DSL — уже есть DSL (аля редактор бизнесс-процессов), но в некоторых кейсах надо больше гибкости и следующий шаг — перейти к коду.
вообще тема холиварная и мой вопрос не в ней, она уже подробно разобрана, см. например в СВ про Дракон.
MH>>>но не уверен, что этого достаточно. MH>>>если реализовать эти запреты, остаются ли варианты как их как-то обойти и всё таки создать/вызвать запрещённые объекты/методы? S>>Если честно — то риск есть всегда. В основном — в виде всяческих транзитивностей. Например, вызов каких-нибудь десериализаторов: в "пользовательском" коде вызовов рефлексии нету, а вот в коде, который он импортирует — есть. MH>он импортирует строго ограниченное подмножество.
А что именно он импортирует? Надо смотреть, не завелось ли там чего-то, что можно творчески эксплуатировать.
Вон, никто же не ожидал, что в Адобовском коде интерпретации шрифтовых хинтов можно выполнить stack underflow и выполнить злонамеренный код под правами текущего пользователя.
MH>там советует известный местный токсик, с которым вести дискуссии неплодотворно.
Я стараюсь меньше обращать внимания на людей, и больше — на идеи. MH>но этот путь уже пройден, те варианты для которых можно было DSL — уже есть DSL (аля редактор бизнесс-процессов), но в некоторых кейсах надо больше гибкости и следующий шаг — перейти к коду.
Не очень понятно противопоставление DSL и кода. Ведь в слове DSL главная буква — это L. Если не хватает мощности языка — всегда можно в него что-то добавить.
Это проще, чем убирать из языка.
Тем более, что, возможно, анализировать надо будет не C#, а MSIL. Я вот сходу не возьмусь напилить с нуля анализатор, который бы отлавливал всё опасное (надо смотреть, к примеру, как именно выглядит dynamic на уровне MSIL) MH>вообще тема холиварная и мой вопрос не в ней, она уже подробно разобрана, см. например в СВ про Дракон.
Дракон тут имхо ортогонален вопросу. Он же не про безопасность, а про определённую графическую нотацию, которая предотвращает синтаксические ошибки.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, MadHuman, Вы писали:
MH>Хочется для написания кода использовать C#
сишарп итак мало что может, а вы его еще хотите обрезать.
Для бизнес логики обычно используют скриптинг.
только операции с объявленными объектами и примитивными типами(строки, числа, даты).
типа: salesforce scripting language
еще видел в дельфи какой-то паскаль, на котором писались формулы для компонентов midas
ну и 1с.
Здравствуйте, MadHuman, Вы писали:
MH>Хочется для написания кода использовать C# и компилять код в сборку. Но требуется обеспечить безопасность, чтоб не могли делать сис вызовы в ОС, не могли лезть в файловую систему.
Создать список допустимых типов (или типов и методов) и конструкций (например, DllImport в топку). Обрабатывать код Розлином и через визитер проверять, что вызваны методы исключительно из списка разрешенных. Как вариант, принимать на вход готовые сборки и сделать их анализатор на базе dnLib.
MH>Есть вариант — поднимать рядом подпроцесс (возможно в контейнере), тогда всё получается, но для скорости хотелось бы инпроц (чтоб напрямую получать ссылки на объекты хост-приложения и тп).
Тут вопрос в задаче, которую нужно было описать. Если, например, вопрос в обработке каких-то данных, то межпроцессный вызов для передачи результатов может быть не особо критичным. Скажем кладешь данные в файл. Вызываешь метод плагина по RPC и передаешь ему пути к входному и выходному файлу. По завершении читаешь получившийся файл. В общем, главное не делать очень много вызовов к серверу. Если это десятки в секунду и данные не огромные, то вполне потянет по RPC.
ЗЫ
Но вообще, это паранойя. Если у юзеря есть права на машине он может и без ваших плагинов наворотить дел или нарваться на вредоносное ПО. У вас код плагинов из не вызывающих доверия источников может приходить? Вы сборки подписываете, кстати? Если нет, то вам и так можно подсунуть все что угодно. Дотнетные процессы вообще не надежны. Вам могут подсунуть вредоносный код внедрив его в код фрэймворка.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, Serginio1, Вы писали:
S>Ну в 1С можно нетовские библиотеки напрямую использовать! S>Использование классов .Net в 1С для новичков
Логично, .net это развитие COM-технологии.
Здравствуйте, vaa, Вы писали:
vaa>Здравствуйте, Serginio1, Вы писали:
S>>Ну в 1С можно нетовские библиотеки напрямую использовать! S>>Использование классов .Net в 1С для новичков vaa>Логично, .net это развитие COM-технологии.
Неее. В .Net сделано удобное использование и совмещение с СОМ
СОМ это межьязыковой стандарт со своим менеджером памяти аппартаментами и прочими плюшками.
Вот как раз с СОМ .Net плохо совметим ибо Release нужно вручную вызывать, а не автоматом как это делается в нативных языках.
Приходится много приседаний делать.
Кстати ы 1С сделали возможность вызывать COM в песочнице
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, MadHuman, Вы писали:
MH>>Хочется для написания кода использовать C# и компилять код в сборку. Но требуется обеспечить безопасность, чтоб не могли делать сис вызовы в ОС, не могли лезть в файловую систему.
VD>Создать список допустимых типов (или типов и методов) и конструкций (например, DllImport в топку). Обрабатывать код Розлином и через визитер проверять, что вызваны методы исключительно из списка разрешенных. Как вариант, принимать на вход готовые сборки и сделать их анализатор на базе dnLib.
да, так и думаю делать (обрабатывать анализатором). есть анализатор BannedApiAnalyzers как раз позволяет выявлять и запрещать заданные типы/методы.
VD>Тут вопрос в задаче, которую нужно было описать. Если, например, вопрос в обработке каких-то данных, то межпроцессный вызов для передачи результатов может быть не особо критичным. Скажем кладешь данные в файл. Вызываешь метод плагина по RPC и передаешь ему пути к входному и выходному файлу. По завершении читаешь получившийся файл. В общем, главное не делать очень много вызовов к серверу. Если это десятки в секунду и данные не огромные, то вполне потянет по RPC.
это понятно. в задаче как раз требуется много мелких взаимодейтсвий с 100500 функциями/пропертями хоста и часто выполняющихся (много тысяч в сек) .
VD>Но вообще, это паранойя. Если у юзеря есть права на машине он может и без ваших плагинов наворотить дел или нарваться на вредоносное ПО. У вас код плагинов из не вызывающих доверия источников может приходить? Вы сборки подписываете, кстати? Если нет, то вам и так можно подсунуть все что угодно. Дотнетные процессы вообще не надежны. Вам могут подсунуть вредоносный код внедрив его в код фрэймворка.
у нас юзер присылает исходник который мы затем на лету компиляем в инмемори асембли и юзаем, не готовую сборку.
пока мне видится что анализатором можно ограничить всё что нужно, и это проще чем заморачиваться выделением в подпроцесс и организацией маршалинга для 100500 методов/пропертей апи хоста.
Здравствуйте, MadHuman, Вы писали:
MH>Всем здравия! MH>Есть задача в приложении исполнять пользовательский код (что-то типа плагинов), реализующий разные хотелки бизнес-логики.
Здравствуйте, MadHuman, Вы писали:
MH>Хотелось бы понять, если в этом направлении пойти, задача решаемая? кто что думает?
Только out-of-process с обрезанными в ноль правами. Или же пишите плагины на Идрисе, с обязательной тотальностью в коде (разумеется этого делать никто не будет).