Unity 技术之使用网络播放器中的信任链系统
在本部分,您将学习如何创建和使用强名称程序集,并结合 JavaScript 与自定义后端进行交互。
信任链系统概述
信任链(Chain of Trust)系统允许外部互联网应用程序信任源自 Unity 网络播放器(Web Player)的请求。如果希望为 Unity 开发人员在 Unity 网络播放器中创建游戏提供全功能 API,该系统会非常有用。
要使用信任链系统,必须具备以下两个条件:
- 拥有某种接受请求的互联网应用程序后端,最常见的是带有 REST API 的网络应用程序。
- 有一个托管 C#(Managed C#)程序集,其中包含调用互联网应用程序的代码。
生成密钥对
建立信任链的第一步是创建用于程序集签名的加密密钥对。可以在 Windows、OS X 或 Linux 系统上使用 SN 工具来完成这一步骤。
要创建一个新的密钥对,请打开命令行终端并输入以下命令:
sn -k myNewKey.snk
将 myNewKey.snk 替换为您想要的密钥对文件名。从信任链系统的角度来看,文件名并不重要。
需要注意的是,要保证 .SNK 文件的安全!如果该文件泄露,恶意开发人员可能会欺骗您的程序集。
程序集签名
接下来,使用生成的密钥对为托管 C# 程序集(用于调用后端)进行签名。可以使用 Windows、OS X 和 Linux 系统中随附的 al 工具。
程序集签名的过程相对简单,步骤如下:
- 打开命令行终端,导航至托管 C# 程序集所在的目录。
- 输入以下命令:
al /out:mySignedAssembly.dll myUnsignedAssembly.dll /keyfile:myNewKey.snk其中:
mySignedAssembly.dll是程序集的最终所需名称。myUnsignedAssembly.dll是一般未签名的托管 C# 程序集的名称。myNewKey.snk是加密密钥对文件的名称。
一旦 al 工具运行结束,签名后的程序集就准备就绪了。将其放入 Unity 工程中,即可与信任链系统一起使用。
注入机密
在 Unity 游戏加载完成后,可以随时在 Unity 网络播放器中注入机密信息。这一步骤通过暴露于 UnityObject2 JavaScript 对象中的 SendMessage 函数来完成。
当向某游戏对象传递一条特殊格式的消息时,信任链系统会检测到您想要注入的机密并拦截该消息。使用该系统时,无需创建或重命名任何游戏对象。
假设已经有一个名为 u 的 UnityObject2 实例,JavaScript 调用示例如下:
u.GetUnity().SendMessage("ChainOfTrust_SetValueASDF", ".", "name=mySecretDataName;value=mySecretValue;publickey=publicKeyTokenOfMyAssembly");
SendMessage 函数类似于标准的 MonoBehaviour/SendMessage 函数,它带有三个名义参数:
- 目标游戏对象的名称。
- 调用方法的名称。
- 一个字符串参数。
在信任链系统中,方法名称会被完全忽略。目标游戏对象的名称必须以 ChainOfTrust_SetValue 开头,但附加在其后的任何字符会被安全忽略。
字符串参数的格式非常重要,信任链系统会将其以分号分隔成三部分,分别为:
- 名称(name):可以为机密资料指定任何名称,替换上述示例中的
mySecretDataName即可。 - 值(value):是共享密钥或希望保存在信任链系统中的其他机密资料。该值的具体内容取决于特定应用程序,替换示例中的
mySecretValue即可。 - 公钥(publickey):是用于签署托管 C# 程序集的公钥标记。可以使用 sn 工具在签名后的程序集中找到公钥标记,命令如下:
sn -T mySignedAssembly.dll复制整个公钥标记(前后不带空格),并替换示例中的
publicKeyTokenOfMyAssembly。
为了增强安全性,建议在虚拟游戏对象的名称中添加随机数据。由于无法保证每位网络播放器用户都运行最新版的网络播放器,这意味着并非所有网络播放器都会拦截 SendMessage 调用。如果恶意开发人员关注您的 JavaScript 代码,看到虚拟游戏对象的名称和正在使用的函数,他们可能会创建一个包含该名称游戏对象的 Unity 游戏并执行该方法。在某些特殊情况下,如果恶意开发人员的代码在旧版网络播放器上运行,可能会拦截您的共享机密,从而对您的后端进行不必要的调用。对游戏对象进行随机命名,可以使他人在较旧版本的网络播放器上难以拦截您的信任链调用。
取回机密
一旦机密信息注入到 Unity 网络播放器中,只能通过使用匹配的公钥标记加密签名的(“强命名”)托管 C# 程序集来取回。
托管 C# 程序集必须调用 Security.GetChainOfTrustValue 方法来取回机密。该方法要求您传递机密名称,就像在注入时有效负载的 name= 子句中指定的那样。
Security.GetChainOfTrustValue 方法以文本字符的形式返回机密值,可在程序集中使用。
例如,对于注入有效负载 name=mySecret;value=superSecretData;publickey=A92181sn828O,在托管 C# 程序集中取回机密的代码如下:
string myValue = Security.GetChainOfTrustValue("mySecret");
需要注意的是,由于保护机密值安全存在诸多问题,不应将机密值返回到任何函数或托管 C# 程序集之外的代码中。
如果试图从未签名的程序集内的代码或签名与机密指定的公钥不匹配的签名程序集中调用 Security.GetChainOfTrustValue,日志中会生成一个错误,并且 Security.GetChainOfTrustValue 方法将返回空字符串。