19

我想制作一个包含专有公式和其他知识产权的 Excel 工作簿。我很可能会在 Visual Studio 2010 中使用 C# 制作此工作簿。

这些项目中的代码受保护程度如何?C# 中的反射问题是否仍然适用于这些工作簿项目?如果是这样,是否有专门针对这些类型的工作簿的混淆工具?

添加到这个问题 - 好的'ole VBA怎么样?如果我们要走 VBA 路线,是否也有办法保护该代码?

4

3 回答 3

19

正如其他答案所暗示的那样,Excel 2003 (.xls) 中的 VBA 安全性存在缺陷;密码只是有点烦人,通常对于开发人员本人而言。恕我直言,即使 Excel 2007+ (.xlsx) 中的 VBA 安全性要好得多,使用 VSTO 也绝对会更好,更不用说几个世纪以来未见改进的 VBA IDE(尽管正确的 VBE 添加并非如此) -在...)。

一个解决方案可能是在您的 VSTO 项目调用的单独库中编写合理的代码;您可以公开显示为“黑匣子”的函数(即公式功能的抽象),不是复杂的公式;没有源代码的任何人都无法使用它的实现方式),没有 dll 就无法计算工作簿(到处都是)。#NAME?

例如=some proprietary formula returning a Smurf,用户将看到而不是=Smurf(SomeTableColumnName, SomeRangeName, SomeRangeReference, SomeCellReference)。当然,这是以性能为代价的,所以我只会为保护真正重要的东西这样做。

我认为一个设法从这样一个侧边库中提取专有公式的用户应该离开它们——在这和 Alt+F11 之间,有相当大的一步;专有代码与任何其他 .net 程序集一样“受保护”。

更新

仍然不使用任何第三方库,如果专有代码不需要Excel 互操作性,一个更好的解决方案可能是在 VBA中创建函数(即将Excel 互操作部分保留在 Excel 中)并且只传递原始类型(VBA Integer=> .net Int16; VBA Long=> .net Int32,字符串等)到一个 COM 可见的库,甚至不需要使用 Excel 互操作;它将是 COM 互操作而不是 Excel 互操作,并且性能影响将显着降低,尽管仍然存在(它仍然是 .net 托管代码与非托管 COM“对话”)。

VBA 代码的职责是读取和写入工作表,COM 可见库的作用是执行由 VBA 代码传递的值进行的计算;当然,用户可以轻松访问 VBA 代码(Alt+F11),但他们再次无法访问实际的计算实现。然后 VBA 代码可以受密码保护,没有 DLL 的计算结果将是0's 或#VALUE!,这取决于 VBA 代码是如何实现的。

关键是在 Excel 中保留 Excel-specifics并让 .net 库在不引用 Excel 互操作程序集的情况下获取它可以获取的位置 - 例如,VBA 函数将获取单元格引用,获取其值(可能验证它)并传递它到 .net 程序集,它将返回 VBA 将返回给 Excel 的另一种原始类型。

另一个优点是,如果您曾经将 Excel 工作簿“转换”为 Web 应用程序,则可以重复使用带有专有计算的库代码。

于 2013-05-08T00:06:52.373 回答
11

供将来参考:这里有 2 种新的创新产品可帮助您解决确切的问题:

1) https://HiveLink.io : - 使用 HiveLink,您可以创建电子表格的“轻量级”版本,将其提供给您的用户,但它不包含任何敏感的 VBA 或计算公式。您从轻量级电子表格中剔除知识产权,并向您的用户发送下载此电子表格的邀请。当您的用户输入他们的输入数据时,HiveLink 会将数据传送到您的原始电子表格以处理数据,然后自动将结果返回给用户。

这种方法的好处是不可能使用 .NET 反射甚至汇编代码进行逆向工程 - 因为您完全从他们的计算机中删除了代码。这是最安全的选择,如果您的模型适合输入/输出往返设计,那就太好了——如果您需要即时发生的客户端交互式代码,那就不是很好了。如果您确实需要快速的客户端交互代码,通常这不太敏感,您可以使用工作簿保护,甚至使用DoneEx Excel Compiler之类的东西编译基本代码,并使用 Excel Compiler 和 HiveLink 的组合进行保护。

2) http://FCell.io:这允许您将 .NET 代码直接构建到电子表格中。它甚至在电子表格中带有一个代码编辑器窗口,有点像用 .NET 代码编辑器替换现有的 VBA 代码编辑器。代码编辑器中的对象模型比普通的对象模型稍微不全面,但您也可以创建任务窗格并将它们嵌入到工作簿中进行分发,这样您的用户甚至不需要安装任何东西!我不确定您的代码嵌入到工作簿中的安全性如何,但我 100% 确信如果代码对他们足够重要,人们可以访问您的代码。

进一步评论 Re Mat's Mug 有用的回应:

回复:性能成本 - 实际上,您可能会注意到通过在 .NET 中实现的东西可以显着提高性能,特别是如果您利用多线程,Excel 根本不会使用 UDF 或宏。我已经看到在 .NET 库中重写我的一些客户代码(用于繁重的处理计算)获得了 100 倍的收益。您可能还会发现 .NET 代码比 VBA 更容易维护和改进。我已经将 VBA 代码和功能转换为 .NET 代码进行了大量转换,并且在正确完成时从未遇到过明显的性能问题。

回复:用户应该通过反映 .NET 库来获得访问权限??- 我完全不同意这一点。使用反射访问 .NET 代码非常容易,甚至可能比破解 Excel 的弱密码更容易。如果您确实有想要保护的敏感计算,那么最好使用HiveLink之类的东西完全消除逆向工程的可能性,或使用混淆使其更难/非常烦人。对于混淆,我使用 CryptoObfuscator($) 和 Dotfuscator($$$)。如果没有这个,我不会在 .NET 库中为 excel 共享我客户的敏感模型 VBA 代码。我有时也使用 CryptoLicensing 来允许他们通过为每个用户创建许可证来控制谁可以访问他们的 DLL 功能。

回复:让 VBA 代码负责向工作表写入/读取/从工作表读取 - 我也非常反对这一点。我建议在 VBA 中保留尽可能少的代码并对 .NET 进行高级调用,将读/写留给 .NET 插件。在工作表中使用命名范围来识别输入/输出和数据位置,然后将这些命名范围定义为 .NET 库中的常量。在您的库中,您可以非常轻松地读取范围并写入范围。以这种方式维护起来更清洁、更容易。

在为 Excel 构建任何要从 VBA 调用外部功能的扩展库时 - 您必须使库 COM 可见。有几种方法可以做到这一点:我强烈建议避免使用 regsvr32 在 Windows COM 列表中注册您的库 - 不惜一切代价避免它!

注册库的最佳方法是使用ExcelDna加载它,它允许您在每次启动 Excel 时动态加载 DLL,而无需在注册表中使用 COM 接口永久定义每个类(更新版本时的噩梦)。您最终会创建一个 XLL 文件,该文件可以将 DLL 打包在其中 - 您可以告诉 Excel 在每次启动时加载 XLL,方法是在注册表中放置一个键。好处是这不需要您将整个 COM 接口存储在注册表中,因此管理新版本非常容易。

因此,您的 VBA 代码可能类似于:

Sub Button_Click()
    Call ThisWorkbook.EnsureLibraryInitialized
    Call ThisWorkbook.MyLibrary.ReadRangesAndWriteResults(someInputParam)
End Sub

请注意,VBA 将在运行时查找此方法 ReadRangesAndWriteResults。如果您在 VBA 中公开编译时方法,那么您必须在注册表中注册其 COM 接口签名 - 值得不惜一切代价避免!

这个工作簿模块:

Public MyLibrary as Object

public sub Workbook_Open()
    EnsureLibraryInitialized
End Sub

public Sub EnsureLibraryInitialized()
    Dim addin As COMAddIn
    If MyLibrary is Nothing Then
        For Each addin In Application.COMAddIns
            If InStr(addin.Description, "MyLibrary.COMHelper") Then
                If addin.object Is Nothing Then
                    'complain it can't connect to library, tell user to reinstall it
                Else
                    Set MyLibrary = addin.object
                Exit For
            End If
        Next
    End if
End Sub

回复:Excel 互操作和 .NET 库 - 好点 Mat's Mug,当使用普通的 Microsoft.Office.Interop.Excel 时,这可能是一场噩梦。因为您正在从托管 .NET 环境访问本机代码,所以您必须确保正确清理您的 .NET COM 包装器对象,否则即使您关闭 Excel 并且看起来它已经消失了,您也会获得 Excel 的挂起/僵尸进程/已关闭(在任务管理器中查看,它们可能还在那里!)

我发现处理此问题的最佳方法是使用NetOffice,它基本上是 Excel 互操作模型的克隆,但创建它是为了安全地为您管理所有这些问题。最好也注意 COM 对象的良好安全处理,例如herehere

祝你好运!

于 2015-03-10T16:20:13.653 回答
7

如果您使用密码保存工作簿以作为 XLSB 打开(请注意此不保护工作簿结构等),则工作簿将使用相当安全的加密进行加密(在 Excel 2013 中更强)。
但是用户必须提供密码才能打开它,这不适合某些使用场景。

所有其他形式的 Excel 保护都相对较弱。

最好使用 C++ XLL 来保护 Excel 中的代码。
下一个最好的是 VB6 DLL(但现在这是一项死技术,在 64 位 Excel 中不起作用)
下一个最好的是混淆的 .NET,但您确实需要使用 Addin Express 提供的那种 .NET XLL 接口或 XL DNA 以避免 .NET Interop 和 VSTO 的性能不佳的特性。

于 2013-05-08T15:44:13.323 回答