有人能在对Windows控件进行子类化时解释一下LinkDemand警告吗

本文关键字:解释 一下 警告 LinkDemand Windows 控件 子类 | 更新日期: 2023-09-27 18:22:43

我有这个HeaderlessTabControl,它是经典TabControl的子类。

// From http://social.msdn.microsoft.com/forums/en-US/winforms/thread/c290832f-3b84-4200-aa4a-7a5dc4b8b5bb/
// Author: Hans Passant (nobugz)
public class HeaderlessTabControl : TabControl {
    protected override void WndProc(ref Message m) {
        // Hide tabs by trapping the TCM_ADJUSTRECT message
        if (m.Msg == 0x1328 && !DesignMode) {
            m.Result = (IntPtr)1;
        } else {
            base.WndProc(ref m);
        }
    }
}

当我在我的项目上运行代码分析时,我会收到以下警告:

警告1 CA2122:Microsoft.Security:"HeaderlessTabControl.WndProc(ref Message)"调用到具有LinkDemand的"Message.Msg.get()"。通过进行该呼叫,"Message.Msg.get()"间接暴露给用户代码。查看以下调用堆栈可能会暴露规避安全性的方法protection:->'HeaderlessTabControl.WndProc(ref Message)'
->'HeaderlessTabControl.WndProc(参考消息)'

以及与CCD_ 1和CCD_。我知道我通过这样做暴露了一些代码。有人能解释一下我可能在这里打开了什么样的安全漏洞,以及可能的修复方法吗?

有人能在对Windows控件进行子类化时解释一下LinkDemand警告吗

我想我想问的是,我应该寻找哪些可能的安全漏洞?

让我用五分钟的时间概述一下"传统".NET代码访问安全性。(我们有一个更新、简化的安全模型,应该用于新代码,但了解底层安全模型是有帮助的。)

其思想是,程序集提供证据,比如它们的位置、编写者等等。策略使用的证据并生成与该程序集关联的权限grant集。

当试图执行需要特定权限的操作时,例如创建对话框、访问打印机或写入文件,运行时会发出该权限的请求。需求检查当前"堆栈上"的代码,以确定直接或间接调用当前代码的所有代码。(*)

该需求表示,堆栈上的每个调用程序都必须被授予所需的权限这防止了引诱攻击,即恶意低信任代码调用良性高信任代码,并"引诱"它代表它做一些危险的操作,以伤害用户。由于完全需求检查直接和间接呼叫者,引诱攻击因此被击败。

断言允许高信任代码修改需求语义。断言说:"我是善意的高信任代码,我断言我不能被低信任的敌对来电者引诱为其执行危险的操作。"断言通常与较弱的需求相结合;也就是说,高信任代码断言"即使调用方不能,我也可以安全地调用非托管代码",然后要求"但调用方最好有访问打印机的权限,因为这就是我要使用非托管代码权限所做的"。

需求的问题在于它们的成本很高。你必须做一个完整的堆栈遍历,并查看每个人的权限集。如果操作成本低廉——比如调整位图中的像素——你不想每次都进行完整的需求,因为你会把所有的时间都花在冗余的安全检查上。

因此链接需求。每个受保护方法的调用方执行一次链接请求,这是第一次使用调用受保护方法的代码,并且它只检查受保护方法的直接调用方,而不是执行完整的堆栈遍历。之后,执行链接所需的代码操作,而不需要对调用方进行安全检查。(它确实应该被称为"jit需求",而不是"链接需求",因为所使用的机制是在调用方被jit时检查需求。

显然,这要便宜得多——每个调用方只查看一个程序集的一个检查比每个调用查看堆栈上每个程序集的的一个检查便宜得多,而且更危险

链接需求基本上是推卸责任。链接请求说:"来电者,通过我的链接请求检查,从现在起,你可以廉价地给我打电话。但我现在关闭了安全系统,因此现在有责任确保来电者不会利用我授予你在未来不进行安全检查的情况下给我打的权利来成功攻击用户。"。"

您正在调用一个具有链接需求的方法。所以你面临的问题是:你愿意承担这个责任吗你可以廉价地调用那个方法。您是否愿意保证没有低信任度的敌对调用者可以利用您可以在没有安全检查的情况下调用该方法的事实来伤害用户?

如果您不愿意或无法做出保证,则发布您自己的请求以获得链接所需的权限;这将要求您的所有呼叫者都满足要求。或者,将责任推卸给您的呼叫者:向呼叫者发出链接请求,并让他们完成工作。


(*)正如我喜欢指出的,调用堆栈实际上并没有告诉是谁调用了你,而是告诉你控制下一步要去哪里。由于这些通常是同一件事,所以一切都很好。最终可能会出现"谁打电话给你?"与"你下一步要去哪里?"脱节的情况;在这些环境中,您必须非常小心地使用传统风格的代码访问安全性。更新的"沙盒"安全模型更适合这些场景。

FxCop的警告可能有点过于热心。这里的情况肯定是这样的,这个代码总是会满足CAS的需求,因为它调用了base。WndProc()。它最终调用Control.WndProc(),看起来像这样:

    [SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
    [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.UnmanagedCode)]
    protected virtual void WndProc(ref Message m) {
        // etc...
    }

InheritanceDemand就足够了。您可以放心地忽略此警告。