如何在 Unity 应用程序中安全使用 URL 处理器和 OpenURL

Unity 安全团队致力于帮助 Unity 创作者开发更值得信赖的游戏和应用程序。请关注本系列博客,了解使用 Unity 创建更安全的游戏和应用程序的技巧、技术和建议。
今天,我们将推出一个关于使用 Unity 进行安全开发的持续性系列博客。本系列将提供 Unity 开发人员可直接应用于其游戏和应用程序的内容。我们希望涵盖从基础知识到高级知识的各种主题,侧重于使用 Unity 产品和服务的最佳实践。如果您想了解某个主题,请告诉我们。我们期待您的反馈。本博客的主要重点是概述 URL 处理程序。
URL 和文件处理程序会将文件类型与可以打开指定文件的已安装程序关联起来,但它们也有风险。例如,当你在 Localization 机器上双击打开本地驱动器中的 PDF 文件时,操作系统会参考其文件处理程序列表,并选择为该文件类型分配的程序,因此你的 PDF 文件会由能够正确显示的程序打开。文件处理程序通常使用文件扩展名(如 .pdf - 文件名末尾的后缀)来决定如何处理文件。
类似的机制还有 URL 处理器,它根据路径前缀决定如何打开 URL。无处不在的 https:// 协议就是一个例子,它可以打开你的默认浏览器。常见 URL 方案的另一个例子是 file://c:/windows/system32/drivers/gmreadme.txt;在 "运行 "对话框中输入该 URL 将导致 Windows 在记事本中打开该许可证文件。
URL 处理器是操作系统的一项实用功能,可为用户节省启动应用程序的时间。然而,这种便捷的机制有时可能并不安全。
Unity 编辑器和 Unity 运行时不仅通过使用 .NET 框架,还通过特定的 Unity 脚本 API(即Application.OpenURL),支持以编程方式使用 URL 处理程序。游戏开发者通常使用 OpenUrl,这样当玩家点击游戏中的链接时,就会启动 Localization 系统的网络浏览器。但是,如果游戏开发者没有对传入 Application.OpenURL 的内容进行适当消毒,玩家就可能面临风险。
这种脚本 API 本身并不安全,但在任何情况下,如果在传入的 URL 中使用了不可信任的输入内容,就需要注意了。
不受信任的输入/数据是指任何并非来自受信任来源的数据。那么,什么是可信的消息来源?在本文中,只有启用了严格 HTTPS的端点才应被视为可信端点。
不信任输入的例子有很多。如果要设计反作弊系统,玩家的 Localization 文件系统应被视为不可信任的。如果开发的是 Multiplayer 游戏,所有玩家都应被视为不可信任的。
还有其他方法可以利用公钥-私钥加密等手段保护数据/输入,但这不在本文讨论范围之内。(如果您有兴趣了解更多相关信息,请留言)。
虽然这些处理程序为用户提供了极大的便利,但也存在固有的风险。下面是一个不安全使用 Application.OpenURL 的示例:
using UnityEngine;
使用 System.Collections;
public class VulnerableBrowserClass:MonoBehaviour {
// 从玩家点击的游戏论坛链接中输入 URL
void OpenBrowser(string url_from_chat) {
Application.OpenURL(url_from_chat); // ←- Badness here; value isn’t sanitized
}
}
图 1.不安全使用 Application.OpenURL 的示例
在本例中,游戏内的评论系统允许用户分享链接;当用户点击链接时,VulnerableBrowserClass.OpenBrowser 函数就会被调用。

图 2.具有潜在危险链接的示例情景
您可以看到,向毫无戒心的用户发送一个指向潜在危险应用程序的链接是多么容易(图 2)。如果直接将 URL 传递给 Application.OpenURL(如图 1 所示),受害者的机器就会立即运行该链接上的应用程序,这样攻击者就有可能控制受害者的系统。
在上图中,攻击者可以格式化上面的链接,使其在聊天窗口中显示为 https://SuperLeetCheats.com/VulnTheGame,但实际链接会指向他们的恶意软件:file://leethaxorz.net/super_malware.exe。这里的问题不在于用户可以互相发送链接,问题在于用户(可能是攻击者)发送的链接未经任何验证或消毒就直接传递给 Application.OpenURL,如上面的代码示例所示(图 1)。如果不进行消毒处理,点击上述链接就会导致 Unity 编辑器将文件直接发送到目标玩家的操作系统,很可能导致执行攻击者的恶意软件。
使用 Application.OpenURL 的最安全方法是永远不要将其与任何不受信任的数据一起使用。仅用于打开来自你的开发人员或服务器并通过可信传输(即 HTTPS)的 URL。
如果使用远程配置(例如,托管新更新的内容 URL 列表),则应确保只能通过 HTTPS 检索这些数据,并严格执行。始终以这种方式检索远程内容。
请注意:HTTPS 无法修复应用程序中由于上述攻击中描述的不信任/未消毒输入而导致的任何漏洞。不过,它可以确保您发送到播放器的数据在传输过程中没有被篡改。
如果您已经决定绝对需要使用 OpenUrl 来处理来自不可信来源的数据,那么您就必须尽最大努力对从不可信来源接收到的输入进行消毒。有几种方法可以做到这一点,如使用 regex 模式匹配、通过 .Net 库构建 URL 或利用外部消毒库。然而,这些缓解措施都无法在 100% 的时间内奏效,而且无论您选择哪种解决方案,如果 Application.OpenUrl(和类似功能)被用于不受信任的数据,都会承担一定的潜在风险。
此外,如上图 2 所示,用户无法知道链接背后的 URL 是什么。至少要提示用户即将访问的完整 URL。但你不应该认为这是一个稳健的解决方案,因为众所周知,用户会盲目点击他们面前的任何提示。
对于开发人员来说,使用 OpenURL 和文件处理程序非常普遍,尤其是在富媒体应用程序和类似于社交媒体的功能(如游戏内聊天、评论和留言)中,用户通常希望共享互联网上游戏之外的内容。此外,在一些常见的工作场景中,例如编辑配置文件时,可能需要向操作系统传递一个链接,打开用户首选的代码编辑应用程序,以方便用户使用。Application.OpenURL 是支持文件处理程序的独立于平台的 API,使 Unity 开发人员不必为每个平台编写自己的处理程序。
如上所述,这是大多数操作系统的常见功能,许多语言和框架都支持该功能。请注意使用 Windows APIWindows.System.LauchURIAsync(适用于通用 Windows 平台 [UWP] 应用程序)或可怕的System.Diagnostics.Process.Start;这两个本地 .Net 库都提供了与 Application.OpenURL 相同的功能。LaunchURIAsync 允许从 Windows 的安全应用程序沙盒中启动应用程序,而 Process.Start 可用于启动 Localization 上的任何可执行文件。此外,一些本地操作系统调用也提供了相同的功能,例如 Apple 的open(_:options:completishHandler:)。如果将不受信任、未经消毒的输入传递到这些 API 中,所有这些类型的 API 都很容易被滥用。
我们将定期在此发布文章,介绍在使用 Unity 进行开发时,对实践和维护安全最佳实践至关重要的主题。即将讨论的主题包括游戏数据的安全传输和安全软件开发生命周期(SSDLC)的民主化。我们还在努力开源一些内部指导和安全工具。
您是否希望在今后的文章中了解更多有关安全的话题?请给我们留言!
了解有关Unity Security 的更多信息,包括安全公告。
