如何避免不小心在我的 MSI 中分发敏感信息?

How do I avoid distributing sensitive information in my MSI by accident?

如何避免不小心在我的 WiX/MSI 中分发敏感信息?


这是一个Q/A-style问题,使用最简单的方法来避免意外通过您的 MSI 传播敏感信息

Super Condensed: Install Orca, get someone else involved to help and go through the raw tables in sequence and then any custom action code.


所有这一切都是显而易见的 - 如果这发生在你身上并且你在野外拥有敏感信息:你所能做的就是撤回 MSI(希望从下载中撤回 - 它在光学媒体的时代),更改任何密码或任何其他被泄露的内容 - 然后确保您不会再次遇到它。现在是重要的部分,未来如何避免它。

除了以下有关敏感信息的信息外,还请记住,您想要包含在您的设置中的某些文件可能无法合法地再分发table。典型示例是来自 Microsoft 的调试工具或来自第三方 SDK 工具包的调试工具。请仔细阅读文档并避免在您的自定义操作中使用此类 "hacky tools"。


精简版

更新:让我记下来,在我忘记之前,您应该从所有安装文件中删除“downloaded file blocking flag”(通常是 read-only也有旗帜)。

下面的所有建议主要是 1) 使用 Orca 扫描最终的 MSI,2) 查看已安装的设置文件以及随您的 MSI 提供的任何 模板安装脚本 。此外,3) 仔细检查您编译的自定义操作源,并可能改进发布构建配置实践(#ifdef _DEBUG 例如,见下文)。 4) 检查您的脚本自定义操作 通过检查您的 MSI 中的实际内容(提取它们)。至关重要的是:至 5) 从其他人那里获得一些帮助 以进行所有手动测试 - 获得一些同谋 :-)。 认真地:设置与应用程序一样重要 - 要使您的解决方案成功,您有责任让 QA-personnel 和其他人参与测试 - 并告诉他们什么以及如何测试。

我会避免自己尝试自动执行此类检查。数据上的真实眼球是无可替代的。也许社区解决方案会长期提供帮助。它可以成为验证套件的一部分吗? Semi-automatic 帮助可能有效,但完全 auto-magic:算了吧。有太多的方法可以用你所有的绳子搬起石头砸自己的脚。

敏感数据可能是错误的术语,也许"invalid content"更合适。您的应用程序在启动时指向您的测试服务器而不是生产服务器可能会导致问题。自定义操作(有时会泄露敏感数据)可能会弹出意外的消息框,以及除了暴露纯敏感数据之外的类似发布错误。


QA - 漏洞探索

检查意外包含的敏感数据显然与包的一般质量检查有关。它应该与一般测试同时进行。 QA 人员忙于应用程序测试,您确实必须推动此部署测试并制定测试计划。没什么特别的,但请测试所有安装模式(installreinstallrepairself-repairupgradepatchinguninstalladministrative installresume / suspended install(设置重启问题)并且您还应该执行 publishingadvertisement - 如果您有设备和网络来测试它)并测试所有自定义动作功能(彻底)。实际上,您 必须 测试安装、重新安装、卸载和升级,但请测试所有模式。

如果您正在本地化,请在所有版本的所有核心区域进行测试。此外 运行 在德国地区使用英语,反之亦然,仅用于烟雾测试。事实上,在所有地区测试英语——我想这是显而易见的。自定义操作很容易在本地化的机器上失败,该机器由该机器上的随机状态触发(例如,CA 试图访问硬编码的英文路径和异常结果),或者在您的异常处理程序代码或类似的代码中显示一些被遗忘的英文消息框从未在英文框上触发过。糟糕,哦,是的,我经常看到它应该被记为一个问题。

而且我想应该提到一位经验丰富的开发人员的话:“...在发现的每个错误都真正令人惊讶之前,不要让太多人进行测试 ”。还有 - 他更有趣的建议 - pre-releases 留下几个已知的错误并告诉 QA 人员有如此多数量的错误需要查找 - 只是为了集中注意力 :-)。 P.S:我喜欢将这位经验丰富的开发人员称为“The Elder Grasshopper”,或者更广为人知的是“Veggie Boy[=283=” ]”。孔子说:“不要相信可以用(有机)胡萝卜收买的人!

扯远了,言归正传:敏感数据错误包含。


检查 MSI 文件

在检查我的 MSI 文件中的敏感信息时,我尽量保持简单。

  1. 首先 快速 once-over 源文件(WiX、Installshield、Advanced Installer 或任何一个你使用的工具)用于 硬编码 dev-box sins.
  2. 然后注意检查完成的release-candidate MSI 文件 本身。真正的麦考伊。所有 tables,以及一些嵌入内容的提取以进行验证(脚本、自定义操作 dll 等)。
  3. 所有安装模式下的实际安装,如上所述。可以显示敏感内容,但很多其他问题也可以 - 例如弹出意外的消息框 - 有时带有敏感的调试信息(自定义操作测试焦点)。

如何查看?一些脚本检查可能会有用,但根据经验,我并不喜欢它。如果我诚实的话,我更喜欢第二双眼睛而不是花哨的脚本检查。只是我从真正的发布工作中得到的两分钱。

  1. 安装 Orca
    • Orca 与您使用 MSI 时一样精确 - 其他工具通常显示伪造的专有 tables。 Orca 是文件内容的直接视图。
    • 如果您安装了 Visual Studio,请搜索 "Orca" 以快速找到安装程序 - 或者让安装了 Visual studio 的人将安装程序 MSI 发送给您。
    • 您也可以尝试“Super Orca”——但推荐使用 Orca。
  2. 现在 打开你的 release-candidate MSI with Orca - 然后浏览 tables
    • 而且只是说显而易见的:
      • 在真实源代码中强制执行任何更改,不要修补已完成的 MSI。
      • 如果您问我,根本没有 in-situ 修补程序 - 我认为您需要在源代码处进行修复并重建完整的 MSI 文件。然后你标记你的源代码(如果你得到了正确的,old-fashioned源代码控制与美味的修订和标签)。
    • 最易受攻击的 table 可能是:RegistryPropertyIniFile- 但在其他几个位置也可能存在漏洞。
    • 如果您实际使用 MSI GUI:tables relating to GUI 也容易受到攻击。
      • 许多人只是使用标准的 GUI 而不做任何修改。这应该可以消除大部分风险。
      • 如果您有自定义 GUI,则 there are quite a few tables involved in the MSI GUI declaration。我会盯着他们所有人。
      • 也许特别关注:ListBoxComboBoxUITextDialog
      • 显然,特别关注您自己的自定义对话框 - 如果有的话。
    • 第三方工具具有易受攻击的自定义 tables,用于 XML 文件更新等。也关注这些。
      • 任何看起来像 XML文件、SQL更新等...
      • 来自不同供应商的此类自定义 table 越来越多。它们现在涉及各种事物,而不仅仅是配置文件(防火墙规则、SQL 脚本等...)
    • 检查所有包含的脚本。
      • 签入源代码管理,而且...
      • CustomAction table 或 Binary table - 后者要求您流出任何脚本 - 或在其源位置检查它们)。
  3. 检查应用程序安装的所有设置文件(通过 MSI 的文件 table)。
    • 具有硬编码设置的 INI 文件可以通过文件 table 安装,因此它们的值在 Orca 中不可见(与显示 INI 的所有字段的 INIFile table 相对)写)。
      • 这里的区别本质上是文件是作为文件处理还是作为一组 group-value 对来处理,例如写入 INI。后一种方法是 "correct" 方法。
      • 请注意,某些 INI 文件可能需要作为文件安装,如果它们具有 non-standard 格式(额外的字段和各种与正常相反的奇怪之处 key-value 对格式),甚至更常见:INI 文件可能有巨大的 注释部分 ,其中包含您想要保留的帮助信息(通常用于开发人员工具)——而您不能通过 INI文件 table。然后选项是将其安装为文件。
    • 其他设置文件,例如 XML 文件可以用同样的方式安装。事实上很多时候。
      • 如上所述,第三方工具通常支持从可在 Orca 中查看的自定义 table 编写更新。
      • 可以有很多这样不同的tables(加密字段?里面有什么?)
    • 像这样包含的文件通常由开发人员维护,但检查仍然是发布责任。做一个administrative installation (further links in linked answer) of your MSI and check the extracted settings files in the created network image. msiexec.exe /a "Your.msi", or setup.exe /a (Installshield), or setup.exe /extract (Advanced Installer). .
  4. 检查支持批量安装脚本Powershell脚本其他形式的脚本使用您的设置 - 意图进行软件的实际安装。
    • 有时您会看到 ready-made 脚本与一些设置一起交付以帮助自动部署,通常某种形式的硬编码信息可以潜入此处(UNC 路径,甚至 IP-addresses,或其他类型的测试数据”)。
    • 根据我的经验,这些脚本有时作为单独的下载提供,可能是事后才想到的,最终被 QA 忽略了。
    • 在 QA 和测试期间积极使用这些脚本(如果可用),或者更好:在单页 PDF 中记录大规模部署(更通用且更不容易出错)。
  5. 警告:编译的自定义操作 仍然可以包含敏感内容,即使在 Orca 中没有任何内容可见 - 很明显。有时一时冲动很容易忘记。这是非常关键的(新的最爱词)——回到源代码。
    • 编译的自定义操作不是直接 "viewable" 所以任何硬编码的敏感内容都是 "less exposed"。
    • 但是,错误的 hard-coded IP 地址可能会导致您的所有用户尝试连接到您的测试服务器或您自己想要的任何其他服务器...我怀疑这不会在设置过程中发生,但在第一次应用程序启动期间。
    • 再次:寻求帮助 - 第二双眼睛会为您省去麻烦,但这次让他们也阅读实际的源代码。告诉他们关注意外的 hard-coded 值和奇怪的定义 - 任何看起来 "experimental" 的东西。
      • 这样的“白框”或"transparent" QA 在这里可能很好。招募另一个 开发人员 ?我会专注于 "weird stuff" 的代码而不是测试实际功能(即用于黑盒测试)。
      • 显然,代码应该与 MSI PUBLIC PROPERTIES 一起工作,仅适用于用户输入的值或在命令行设置的值。任何硬编码的东西都不应该存在。然而,在现实世界中,大多数开发人员最终会在调试版本中设置一些硬编码的内容。
      • QA 专业人员 应该被告知如何测试相同的自定义操作“黑盒”显然 - 以及第一个应用程序启动到测试正确的值是否写入了它们要去的地方。
      • 您能否为他们知道存在并且知道如何使用的 QA-guys 提供一些方便的应用程序级日志记录(并且他们期望检查它? ).然后,在他们发现您的发布应用程序命中您的内部测试服务器而不是您的生产服务器之前,您应该只需要几分钟。
    • 对于编译的 C++ 自定义操作,如果您坚持硬编码,我建议您使用良好的挑剔调试实践。使用 #ifdef _DEBUG 来包装 debugging message boxes 和任何 hard coded test variables。请参阅下面的 C++ 片段。这意味着发布版本中根本没有实验值(pre-processor 将删除所有调试结构)。
    • 也许也将 NOMB 添加到您的发布版本中?也请参见下面的示例 - 应该防止流浪发布构建消息框 - 本质上定义 "forbids" 他们(其他,可能定义:How to tame the Windows headers (useful defines)?)。
      • 我只是简单地测试了一下。尽管我在发布版本中弹出了相当一部分被遗忘的 C++ 消息框 - 我不得不承认 - 幸运的是没有灾难(敲木头等等等等)。
      • 请记住,这样的消息框可能会在没有任何警告或明确原因(通常没有日志消息)的情况下以静默模式远程神秘地停止设置 运行。
      • 此类消息通常可能由某种错误情况或异常情况触发,大多数安装通常不会触发 - 因此它突然出现在某些 PC 上。远程部署时您无法恢复。设置不正确 roll-back,只是卡住了。如果没有用户在本地登录,也无法在机器上关闭它。不是严格意义上的敏感信息,而是相关的(盒子上究竟显示了什么?),以及测试自定义操作时需要注意的事项。
      • 一个很自然的问题是有没有办法让message-boxestime-outauto-magically?我简要地 smoke-tested 这个建议的 MessageBoxTimeout 方法(来自 user32.dll),它似乎甚至支持上面的 NOMB 功能以及超时。换句话说,您可以在发布版本中将消息框设置为禁止,在调试版本中设置为 time-out。未彻底测试。
    • C++ 不是我的事,使用贵公司定义的发布版本的最佳实践。也许寻找定义和字符串变量。或者所有设置都可能位于仅包含在调试版本中的设置文件中(但奇怪的东西往往会到处蔓延)。
    • 对于托管代码,我问自己的问题是:如何de-compilable这个托管二进制文件?我在这里没有什么经验。我从未花时间 de-compile 托管二进制文件。
      • 无论如何,代码中应该没有任何敏感内容 - 除非你有隐藏的私钥、许可证密钥或类似奇怪的东西 - 我绝对不会这样做,留给应用程序去做
      • 对于为您的应用程序设置试用期等功能,我想您可能希望 "hide the implementation" 更好。某种混淆可能很常见,我没有跟上速度。也许这是 .NET 世界中更大的问题之一? 题主:请不吝赐教.
      • 我会关注与上述相同的问题:调试错误地包含在发布模式二进制文件中的构造和错误的 links 以及设置为测试服务器和测试资源的路径。
  6. 不小心在你的官方版本中包含调试构建二进制文件
    • 还有一个在某些情况下很容易发生的问题:您在 MSI 中包含了自定义操作 DLL 的调试版本
    • 这显然会发生在您设置中的任何文件中,不仅仅是您的自定义操作 DLL,而且自定义操作 DLL 特别是 "hidden" 在您构建后的包中(嵌入在 MSI 的二进制文件中 table - 验证它)。
    • 也许确保将 d 添加到您编译的自定义操作 dll 的文件名中 - 或者与此相关的任何其他文件?即使这会给您带来一些额外的工作?
    • 我不确定 "sensitive" 调试 dll 到底是怎样的(专业的 C++ 专家必须详细说明)- 但我肯定不想无意中在我的设置中分发此类文件。我有时(很少)为 QA 团队制作调试构建 MSI 文件,仅包含用于测试目的的调试二进制文件和符号,在我看来,这些设置应该在一两个月后过期,并且永远不容易安装,也永远不会在 QA 团队之外使用.可以添加安装密码,但 MSI 是一种开放格式,仍然可以提取。没有戏剧性,我想只是要记住和管理的事情。
  7. 现在这有点推动 "sensitive data" 的主题,但是对您打算 签名的任何内容进行 彻底的恶意软件扫描 怎么样?以数字方式 并以public 方式发布?签名的恶意软件不是您想要体验的。
    • 验证您在发布文件(如果有)上的数字签名。使用 UAC 等进行测试...
    • 也许使用 Virustotal.com 或等效的恶意软件扫描服务/解决方案来扫描您最终的 MSI 文件中的恶意软件(或误报)。
    • 使用procexp64.exe (direct download of Sysinternals Process Explorer) to scan all your running processes after test installation. See some suggested usage steps for the tool here.
    • 使用这些工具也可以帮助您 消除 false-positives 的解决方案。随着安全软件加强安全性和恶意软件变得越来越普遍,这个可怕的问题似乎变得越来越严重。
      • (请参阅 link 中的问题 7),因为文件被反复隔离,然后由 Windows 安装程序通过 self-repair 放回。
      • 误报讽刺对于真正的恶意软件,您告诉您的用户重建他们的计算机。 对于 false-positive,您面临着与安全软件供应商解决问题的压力。现在如何为数十种安全工具和套件做到这一点?

仅在 C++ 自定义操作中调试消息框:

我使用消息框将调试器附加到 C++ 自定义操作代码。如何避免这些小动物出现在发布版本中?这是一个建议:

#ifdef _DEBUG //Display Debug information only for debug builds
     MessageBox(NULL, "Text", "Caption", MB_OK|MB_SYSTEMMODAL);
#endif

高级 C++ 人员会立即看到他们应该为这个做一个更好的宏 - 包装它 - 我不是 C++ 高手,所以我暂时不说(SafeMessageBox?DeploymentMessageBox?)。

stdafx.h 中,也许另外启用 NOMB(应防止 MessageBox 编译,除非用 #ifdef _DEBUG 包装 - 使 MessageBoxes 仅在调试版本中可用):

#ifndef _DEBUG // Forbid MessageBox in Release builds
    #define NOMB
#endif

(我敢打赌,这可能会成为您有史以来最讨厌的定义之一 :-)。谁闻到了注释掉的部分?我不会使用 #undef 添加一个 ad-hoc 发布消息框 - 它破坏了整个保护功能 - 可能恰恰导致你希望避免的事情:一个杂散的消息框。如果必须的话,也许只需注释掉 stdafx.h 中的 #define,然后再次启用定义 - 通过构建过程自动 - 对于真正的 public 发布构建,会触发任何杂散消息框的编译错误)

并且如上所述,您可以尝试新的 MessageBoxTimeout 方法(来自 user32.dll,从 XP 开始显然可用)来显示没有得到 "stuck" 但超时的消息框在指定的秒数后。不适用于发布,但可能对调试和 QA 有用。

一些上下文#ifdef DEBUG versus #if DEBUG。真正了解 C++ 的人可以根据需要随意澄清或详细说明。以上来自一个非常古老的C++项目。

基本上就是这样 - 几乎不是火箭科学 - 只是 "trifles that bite"。关于以下主题的一些进一步讨论,但恕我直言,无法替代手动扫描。我的诚实建议,抓一些人(经理就好了:-)将他们作为同谋拉进来!),为他们安装 Orca 并告诉他们单击 tables 并查看所有设置文件 - 并让开发人员帮助编译自定义操作代码.仅仅查看原始的 Orca tables 甚至可以有效地发现其他错误或缺陷。


敏感信息

在开发过程中有很多机会意外地将敏感信息包含在 MSI 源中:login credentialspasswordsdatabase connection stringsuser namesshare nameIP-addressmachine namesftp passwordsweb host login credentialsother sensitive data.

您的 MSI 显然根本不应包含任何此类敏感信息 - 除非您想指向 您自己的 web-site 当然可以,或者提供 联系电子邮件 电话号码 。然而,其他任何事情几乎总是不受欢迎的 - 由于开发实验(通常在 脚本自定义操作 - 或编译的自定义操作 - 更糟糕的是,上面建议的 Orca 审查方法没有检测到table,但通常不会被用户 view-able 检测到,除非它被显示通过意外的消息框 - 或者如果 .NET 托管代码被反汇编)。

如果安装确实需要,这样的 "sensitive" 信息应该是最终用户在安装时设置的参数(属性),可以通过安装程序的交互式 GUI 或通过 PUBLIC 设置安装安装程序时在命令行中进行属性或转换。这里有一些关于使用转换和 PUBLIC 属性的信息:How to make better use of MSI files 用于 MSI 文件的静默公司部署(linked 答案还提供了对 MSI 的 ad-hoc 描述更一般意义上的问题和好处)。