某些库代码需要调入非托管代码(例如,Win32 等本机代码 API)。因为这意味着超出了托管代码的安全范围,所以需要适当地小心。如果您的代码是不受安全性影响的,那么您的代码以及调用它的任何代码都必须具有非托管代码权限(指定了 UnmanagedCode 标志的 SecurityPermission)。
然而,调用方具有如此强大的权限常常是不合理的。在这种情况下,受信任的代码可以充当中介,它类似于保护包装代码中所述的托管包装或库代码。如果基础的非托管代码功能是完全安全的,就可以直接公开它;否则,需要先进行适当的权限检查(请求)。
如果您的代码调入非托管代码,但是您不希望要求调用方具有访问非托管代码的权限,则必须断言该权限。断言会阻止对帧执行堆栈审核。您必须非常小心,不要在这一过程中制造安全漏洞。通常,这意味着您必须请求调用方拥有适当权限,然后使用非托管代码来仅仅执行该权限所允许的操作。在某些情况下(例如,获取一天中的具体时间的功能),非托管代码可以直接公开给调用方,而不需要进行任何安全检查。在任何情况下,任何执行断言的代码都必须对安全性负责。
因为任何提供到本机代码的代码路径的托管代码都是恶意代码可能攻击的目标,所以,在确定可以安全使用的非托管代码以及必须以何种方式来使用该代码时,需要特别小心。通常,不应直接向部分受信任的调用方公开非托管代码。对于部分受信任代码可调用的库中所使用的非托管代码,在评估其安全性时,主要应注意两点:
-
功能。非托管 API 是否提供了不允许调用方执行潜在危险操作的功能? 代码访问安全性使用权限来执行对资源的访问,因此,应考虑 API 是否使用文件、用户界面或线程处理,或者代码访问安全性是否允许公开受保护的信息。如果是,则包装它的托管代码必须请求所需的权限,才能输入代码访问安全性。此外,在没有权限保护时,内存访问必须遵循严格的类型安全。
-
参数检查。普通攻击向已公开的非托管代码 API 方法传递意外参数,试图使它们超越规范而运行。此类攻击的一个常见示例是使用超出范围的索引值或偏移量值的缓冲区溢出,就像任何可能利用基础代码中的 bug 的参数一样。这样,即使非托管代码 API 对部分受信任的调用方来说在功能上是安全的(在应用必需的请求之后),托管代码也必须彻底检查参数有效性,以确保恶意代码不能使用托管代码包装层执行非预期的调用。