有没有办法阻止一个C#插件访问程序中的主要C#应用程序?

6
我有一个程序和一个简单的插件架构,其中插件实现了通用接口,主程序加载实现该接口的所有插件。这是我迄今为止发现的最常见的自定义插件架构,所以我正在使用它。
我没有使用Microsoft的MEF,并且我有我的原因不这样做。就让它保持这种状态吧。
问题在于,当插件被加载时,无论它们对主程序及其表单/类等多么“盲目”,它仍然可以访问System.Windows.Forms.Application,并因此可以访问我的应用程序及其当前运行的表单/方法/控件等。
我不希望出现这种情况。有没有一种方法来限制插件对主应用程序的访问?
编辑:关于插件的更多信息
我们(我的老板和我)目前正在讨论插件需要做什么。它们都显然需要添加功能,但我们最初决定为每个插件提供对当前运行的表单的访问权限,以便它可以直接向表单添加控件和事件。这是基于假设只有我们开发人员会编写它们的前提下。
现在我们正在考虑第三方插件的可能性,而最初的设计显然像一扇敞开的门上挂着一个“禁止进入”标志或者万圣节上挂着一个碗里放着单独的彩虹糖果,上面写着“拿走一个”。

如果插件引用了Windows.Form dll,你能否拒绝它? - hungryMind
1
@hungryMind 如果有人使用反射来访问类型,那么很容易绕过引用检查。字符串攻击将会绕过此项检查。 - Tim Lloyd
4个回答

4
如果您可以让插件在它们自己的AppDomains中运行,那么这肯定会增加隔离级别。但是要与它们进行通信可能会有些棘手。不过,如果不了解插件的预期用途,很难知道是否恰当。

4
一种实现方法是将插件托管在自己的AppDomains中。您可以配置这些AppDomains以限制安全性,以防止它们访问主AppDomain中的资源。这确实会使事情复杂化很多,但会为您提供所需的沙箱效果。
AppDomain托管还可以带来额外的好处,如果需要刷新插件,则可以加载和卸载这些域,此外,您还可以保护主AppDomain免受“子”域中崩溃的影响。
更新
针对您关于插件功能的更新,如果您的插件必须直接访问UI元素(例如访问表单以添加控件),则AppDomains无法帮助您。您将无法跨越AppDomain边界直接访问表单,或者在一个AppDomain中生成控件,然后将其跨域传输到另一个AppDomain中。
你仍然可以考虑在另一个AppDomain中托管插件,但是您需要考虑一些代理机制,以便像将控件添加到表单之类的操作可以代表插件进行,而不是让插件直接访问表单。例如,您可以传递一个表单构建器对象,该对象具有诸如 AddButton 之类的方法。然后代理可以代表插件在主域中执行这些操作。通过这种方式,您可以为插件提供有限的API,包括所需事件。

这种方法绝对不是简单的,但是一旦您掌握了基础知识,它并不太复杂。

更新2

自从过去使用AppDomains自己创建插件框架以来,情况已经发生了变化。自3.5版以来,.Net框架中已经支持插件:

MAF - Managed Addin Framework / System.Addin

它支持插件的AppDomain隔离模式,并具有插件加载器等功能。无需自己创建。


有没有示例网站或其他东西解释如何设置这种有限的安全性?是否有一个用于在它们之间通信的示例? - Mike Webb
@Mike 我最近一直在寻找使用AppDomains构建自己的插件架构的好例子。我已经很久没有使用它来编写插件框架了,而且我找到的许多示例都存在问题。这确实非常棘手,所以我不想给你带来会让你抓狂的示例。然后我想起来,微软实际上在 .Net 3.5 中内置了一个插件框架 - MAF: Managed Addin Framework。这个框架处理了很多脏活,因此您不必担心诸如AppDomain隔离和插件加载/卸载等问题。 - Tim Lloyd
@Mike 因为这是一个微软框架,所以有大量的文档和在线内容,这是更好的选择。一个好的开始在这里:http://msdn.microsoft.com/en-us/magazine/cc163476.aspx。 - Tim Lloyd
现在我被限制只能使用 .NET 2.0,但我实际上找到了一些东西。通过基于这些文章中使用的概念的一些自定义代码,我认为我可以使用 sudo-消息传递编写插件架构。第二部分详细说明了使用 AppDomains 的代码。以下是该网站:http://www.15seconds.com/issue/040624.htm - Mike Webb
@Mike OK,.Net 2.0 - System.Addin已经发布。关于AppDomains,这篇文章有很多内容可以帮助你入门,尽管有一些关于程序集被加载到默认域的评论 - 仍然有一些非常好的基础知识:http://www.codeproject.com/KB/cs/dynamicpluginmanager.aspx - Tim Lloyd

1

因此,重新阐述您的主要关注点:

...... 因此可以访问我的应用程序及其当前运行的表单/方法/控件等。

在开始复杂和困难的加载、隔离和限制这些扩展之前,您应该了解一些关于Windows和CLR的知识。首先,任何在计算机上运行的程序都可以使用许多Windows API将代码注入到您的进程中。一旦代码被加载到您的进程中,无论是您还是操作系统,访问CLR运行时并加载程序集和/或在现有的AppDomain中运行代码都相当容易。

了解这一点后,您应该权衡和平衡您为限制“扩展”所做的努力。如果我正在构建类似于此的东西,我会更关心其他事情,而不是恶意的扩展代码操纵我的应用程序状态。例如,以下是您可能考虑的事情:

  1. 只加载经过用户批准的扩展,允许他们控制允许什么,并允许他们稍后撤销扩展。可以参考Office或VStudio。
  2. 确保这些批准的扩展未被篡改,使用代码签名要求(强名称或代码签名证书)。
  3. 考虑有能力撤销恶意扩展的远程运行权限。
  4. 提供一个精心设计的接口API,以便开发人员轻松实现所需的行为。如果他们可以轻松地使用您的接口来完成任务,他们就不需要“黑客”。

除此之外,你真的没有太多可以做的了。正如我所说,即使有上述安全措施,任何人都可以攻击你的应用程序。你的主要关注点应该是不要让用户感到惊讶。因此,在运行YOUR应用程序的代码方面要小心谨慎是明智的,但是一旦用户授予它们访问权限,这些扩展所做的事情并不是您完全可以控制的。

这并不是说AppDomain隔离不会为您提供价值,它可能会;然而,在限制其功能的同时使安全性足够受限将证明是困难的。

更新

“...但是如果你将插件加载到配置有限权限的AppDomain中,它如何使用这个向量呢?”
正如我在我的结论中所说的那样,你可以限制他们在AppDomain内部对非托管代码的访问。这也限制了他们开发可用Windows体验的能力。我预计大多数WinForms应用程序至少使用一个PInvoke调用或非托管COM控件。这种限制可能是可以接受的,但如果不了解他们试图提供的功能,我无法做出判断。
我想说的是,通过安装和批准扩展,您的用户正在接受允许该扩展运行的责任。该扩展所做的事情以及它可能尝试的恶意程度并不是您的责任,当然前提是您加载了正确的代码。这就是为什么我建议将精力集中在运行经过批准的代码上,而不是担心该代码进入您的进程后可能会做什么。”

我理解另一个进程使用Win32调用和代码注入的观点,但是如果您将插件加载到配置有限权限(例如无未托管代码权限)的AppDomain中,它如何使用此向量呢? - Tim Lloyd
由于SO通知的性质,如果您在我的@用户名处提到我,我将不会收到您的回复通知。我发表了我的评论,因为您的回答语气可能会让人们认为使用AppDomains是无望的,涉及代码注入。 - Tim Lloyd

0

处理这个问题的最佳方式是公开一个经过文档化的插件API。如果您的插件以完全信任的方式运行,即使在其自己的AppDomain中运行插件,它也可以将自身注入到应用程序中 - 然后只需要有人提供包装器,所有插件都回到了它们开始的状态。如果您的API允许插件以简单、一致和文档化的方式提供所需的功能,那么插件开发人员将使用它。

以下是WPF、Windows Forms和经典Spy++的外部UI钩子(均带有源代码)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接