【问题标题】:Implementing untrusted plugins in .NET web application在 .NET Web 应用程序中实现不受信任的插件
【发布时间】:2013-04-10 18:48:51
【问题描述】:

我想开发一个接受来自用户社区的插件的应用程序,类似于 Chrome 或 Firefox 的做法。这将是一个 Web 应用程序,因此单个用户的应用程序的每个“实例”都将运行不同的插件(插件将作为单例实例加载,但仅对某些用户是“活动的”)。我正计划在 .NET 中实现应用程序,并尝试为插件模型提出一个架构。

这是我想要的属性:

  • 插件完全在我的核心应用程序之外构建,作为单独的程序集。
  • 插件在自己的“锁定”、低信任环境中运行。可能是一个单独的 AppDomain。
  • 插件只能通过我提供的 API 起作用。例如。我会将某种外观作为接口传递给它们,它们只能调用它,而不能调用任何其他程序集。我不能拥有可以在 Web 服务器上任意执行操作的插件,例如影响文件系统。
  • 插件中的致命崩溃不会影响核心应用程序的稳定性。

似乎 System.AddIn 是我最好的选择,但我不清楚如何强制加载的插件仅通过我提供的 API 工作,而不加载任何其他程序集。 System.AddIn 是否提供该功能?另外,System.AddIn 可以与 ASP.NET / IIS 一起使用吗?

除了 System.Addin,我还有哪些其他选择?

【问题讨论】:

  • 你看过 MEF 吗?
  • 您可以看看这个由 Microsoft 创建的 .NET 游戏“Terrarium”,以说明 .NET 的功能。它具有安全插件的概念,因为游戏中的每个生物都是某种插件:terrarium2.codeplex.com
  • @SimonMourier 我会看看那个。如果您想总结他们使用的技术并将其发布在此处,您可以将其转化为答案。
  • @DanielMann MEF 没有提供我需要的隔离或沙盒。 MEF 实际上只适用于“受信任的插件”场景。我正在寻找实现“不受信任的插件”。

标签: .net plugins architecture add-in


【解决方案1】:

看起来您主要关心的是隔离(为了安全性和稳健性)。

因此,您最好的选择是在单独的 AppDomain 中激活您的插件。在此域中,您可以控制允许加载的程序集(请参阅 AppDomainSetup 类)。

您的主要代码也将受到保护,不会在插件内发生任何意外:所有插件方法都必须使用核心对象的副本(除非您传递的对象是从 MarshalByRefObject 继承的,在这种情况下,所有的赌注都是离开)。 addin 方法中的异常可以通过将所有调用包装在 try except 中,或者通过 AppDomain 的 UnhandledExcption 事件来处理。

请记住,跨越 AppDomain 边界会降低性能。该调用本质上是一个远程调用。

另一个潜在的问题是您打算如何管理 AppDomain。我从未尝试在一个进程中创建多个 AppDomain,但我预计会遇到麻烦。为单个域中的多个用户组合插件将挑战您尝试在其中构建的保护

作为对@RationalGeek 问题的回应-UnhandledException event 允许这样做- 有点。您可以在核心域和插件域中订阅此事件,但这样做存在很多不确定性 - 请参阅我引用的文章了解更多详细信息。可能更好的选择是将对 API 的每次调用都包装在 try/except 中

【讨论】:

  • 如果其他应用程序域之一有未处理的异常,我能否充分保护我的核心应用程序不崩溃?
【解决方案2】:

您可以尝试使用 AppDomains 并处理未处理的异常。为避免 appdomain 崩溃,您必须处理 AppDomain.UnhandledException

在上面的链接中,注意以下语句

从 .NET Framework 4 开始,不会为破坏进程状态的异常引发此事件,例如堆栈溢出或访问冲突,除非事件处理程序是安全关键的并且具有 HandleProcessCorruptedStateExceptionsAttribute 属性.

所以你可能需要显式处理一些配置。

我读过很多问题,声称当子域中的不同线程上发生未处理的异常时,会冒泡并关闭父域。如果是这样,那么建议将所有插件加载到一个单独的进程中,每个插件都有一个 appdomain,或者将插件加载到单独的进程中。

我还遇到了关于 SO 的以下问题,我相信您会觉得很有帮助

【讨论】:

    【解决方案3】:

    为什么不直接使用反射并在运行时发现可用插件? Assembly.LoadFile 获取程序集, GetExportedTypes 获取您的对象 使用 Activator.CreateInstance 创建实例

    然后只需在 try 循环中运行插件,以确保它不会影响系统。尽管您需要一些重要的架构来提供实际的稳定性。

    远离 MEF,除非您有复杂的插件管理场景。如果它只是允许用户使用他们的,包括你自己的,那就使用反射。

    【讨论】:

    • 这不会解决与核心的隔离问题,也不会阻止插件访问“未经批准”的程序集。
    猜你喜欢
    • 2021-05-14
    • 1970-01-01
    • 1970-01-01
    • 2016-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-27
    • 1970-01-01
    相关资源
    最近更新 更多