【问题标题】:How do I make sure that my windows impersonation level is valid?如何确保我的 Windows 模拟级别有效?
【发布时间】:2015-02-19 02:09:33
【问题描述】:

我正在处理一个令人讨厌的问题,让我准备好撕掉我的头发。我有一个 C# 控制台应用程序,它使用 Microsoft 的 HttpListener 类来侦听 Web 请求。这个想法是控制台应用程序作为 UserAccountA(低权限)在后台运行。 UserAccountB(管理员等)出现,通过侦听器访问网页,并假冒他或她的身份。 IIS 或 WCF 所做的事情相同。我相信我在 Windows 7 上运行过这个,但现在我在 Windows 8.1 上,它又失败了。也许我从来没有开始,或者也许这是一个新的转折。

如果我通过 Visual Studio 运行程序,我可以使用 Internet Explorer 11 访问它。出于某种原因,它要求我输入本地凭据。我假设这与 IE11 的开箱即用行为有关。一旦我输入它,它就会接受它。我的代码是这样开始的:

    protected virtual void Listen(object o)
    {
        HttpListener h = (HttpListener)o;

        while (h.IsListening && (this.Disposed == false))
        {
            IAsyncResult Result = null;

            Result = h.BeginGetContext(new AsyncCallback(this.ListenerCallback), h);

            Result.AsyncWaitHandle.WaitOne();
        }
    }

而且是这样捡起来的(略):

    protected virtual void ListenerCallback(IAsyncResult Result)
    {
        HttpListener h = (HttpListener)Result.AsyncState;
        HttpListenerContext context = null;
        System.Security.Principal.WindowsIdentity identity = null;

        context = h.EndGetContext(Result);

        identity = (System.Security.Principal.WindowsIdentity)context.User.Identity;

        using (System.Security.Principal.WindowsImpersonationContext wic = identity.Impersonate())
        {
             //method call to process request, under impersonation
        }
    }

在使用两个不同的帐户(一个用于托管,一个用于访问)时,我已逐步完成此代码。我已经使用此语句进行了验证:

   system.security.principal.windowsidentity.getcurrent().name

当前身份确实转换。侦听器配置为使用 NTLM AuthenticationScheme 启动。

我想复杂的部分在于模拟期间调用的方法。我们正在做一些抽象,但让我指出失败的部分。在这种情况下,我们使用 SSPI 连接到 SQL Server - 因此模拟的全部目的是获取客户端的现有登录并优雅地将它们导入 SQL Server。同样,现在,这对一台计算机来说都是本地的。它甚至不在活动目录域中。一切都是本地的,具有本地帐户。开头是这样的:

        System.Data.Common.DbProviderFactory fact = null;

        if (UseSql())
        {
            fact = System.Data.Common.DbProviderFactories.GetFactory("System.Data.SqlClient");
        }

没什么大不了的。我们在另一个项目中不断使用提供程序工厂,没有任何问题(但这只是一个常规的 WPF 应用程序,没有这样的)。在此之后,我们将使用 SSPI 属性设置 SQL 登录字符串。但我们甚至没有做到这一点。这正是它失败的地方,并带有以下消息:

“System.IO.FileLoadException”类型的第一次机会异常 发生在 mscorlib.dll 中

附加信息:无法加载文件或程序集 'System.Data.OracleClient,版本=4.0.0.0,文化=中性, > PublicKeyToken=b77a5c561934e089' 或其依赖项之一。要么 未提供所需的模拟级别,或提供的 模拟级别无效。 (HRESULT 异常:0x80070542)

http://i854.photobucket.com/albums/ab103/srVincentVega/error7_zpsmb1xqrp0.png

我们根本没有使用 Oracle,我假设这只是它在尝试打开 DbProviderFactory 时的第一件事。对我来说,关键是模仿级别的东西。在这个特定的实验中,两个帐户(A 和 B)都是本地管理员。我已经通过本地安全策略确保他们可以在登录后模拟帐户。如果我查看我的事件日志,模拟似乎确实有效......

分配给新登录的特殊权限。

主题:安全 ID:

pc1\userA

账户名:userA

帐户域:pc1 登录 ID:0xC4D0F3F

特权:

SeSecurityPrivilege

SeTakeOwnershipPrivilege

SeLoadDriverPrivilege

SeBackupPrivilege

SeRestorePrivilege

SeDebugPrivilege

SeSystemEnvironmentPrivilege

SeImpersonatePrivilege

我在这里尝试了很多变化,以至于我开始妨碍我自己的分析。我基本上回到了第一方,不知道如何解决这个问题。有没有人有任何建议或提示?这似乎应该是一件非常简单的事情。我不知道为什么我有这么多麻烦。也许我只需要放弃使用 DbProviderFactory 并使用 OleDb 或其他什么。但我还没有确认我可以在模拟后在运行时加载任何库。也许这是要做的事情。但是,我将非常感谢您的帮助。

谢谢,

约翰

最后一件事,这里是复制步骤:

在您的计算机上创建辅助用户。登录以创建配置文件。像往常一样注销并重新登录。以该次要用户身份运行 Visual Studio(有几种方法可以做到这一点,shift + 右键单击​​ VS 图标),并在其中使用此框架创建一个 C# 控制台应用程序:

    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                using (HttpListener h = new HttpListener())
                {
                    h.Prefixes.Add("http://+:8090/");

                    h.AuthenticationSchemes = AuthenticationSchemes.Ntlm;

                    h.Start();

                    Console.WriteLine("Running");

                    HttpListenerContext context = h.GetContext();

                    System.Security.Principal.WindowsIdentity identity = null;
                    identity = (System.Security.Principal.WindowsIdentity)context.User.Identity;

                    using (System.Security.Principal.WindowsImpersonationContext wic = identity.Impersonate())
                    {
                        System.Data.Common.DbProviderFactory fact = null;
                        fact = System.Data.Common.DbProviderFactories.GetFactory("System.Data.SqlClient");
                    }

                    Console.ReadLine();

                    h.Stop();
                }
            }
        }
    }

调试/运行控制台应用程序。只需调用 Internet Explorer(普通版,使用您的主帐户)并访问该 URL (http://machinename:8090)。发生异常

http://i854.photobucket.com/albums/ab103/srVincentVega/error8_zpsilkay0bl.png

【问题讨论】:

  • 根据您执行此操作的方式,您可能需要添加本地规则来侦听 8090 等端口。您可以在提升的命令提示符下执行此操作:netsh http add urlacl url=http ://+:8090/user=(SecondaryAcctName)

标签: c# visual-studio impersonation httplistener


【解决方案1】:

嗯,我读到一半就停在你得到的异常处:

A first chance exception of type 'System.IO.FileLoadException' occurred in mscorlib.dll 

这里的问题是,您用于运行服务的帐户在加载 .Net 框架核心库之前具有有限的访问权限,甚至无法执行模拟。通常用于托管服务的此类帐户在托管服务的节点上具有管理员权限。

此外,要允许模拟,您需要使用本地安全策略 - 本地策略 - 用户权限分配为服务帐户授予执行此操作的权限:

作为操作系统的一部分

此用户权限允许进程在没有身份验证的情况下模拟任何用户。因此,该进程可以访问与该用户相同的本地资源。

身份验证后模拟客户端

将此权限分配给用户允许代表该用户运行的程序模拟客户端。

另请注意,如果您使用 kerberos 而不是 NTLM,则需要在 AD(Accept 目录)中设置 SPN 和委派目标。

我不知道这是否会对您有所帮助,但这些是我们在进行模拟/委托时遇到的问题。

哦,是的,如果您执行多个跃点来执行模拟,则必须将模拟级别设置为委派。

【讨论】:

  • 感谢您的想法。我的两个测试帐户都是本地管理员,您提到的两个 SecPol 功能都已打开。我注销并重新登录只是为了确保它们生效。问题仍然存在。如果我正常运行控制台应用程序,并以其他用户的身份在 Internet Explorer 上运行,它就可以工作。如果我扭转这一点,并以控制台应用程序运行,并正常运行 IE,那么它会失败。我注销并以另一个帐户重新登录,同样的事情发生了。仅当控制台应用程序“运行”时才会发生这种情况
  • 我可能在这里介绍了一个红鲱鱼。我构建了完整的应用程序并将其设置为作为“用户 B”作为 Windows 计划任务运行。所以这是在后台运行的。当我使用 Internet Explorer 连接到它时,它工作正常。我没有收到错误。我验证了模拟是有效的。因此,也许我已经使用“运行方式”功能支持了一些奇怪的安全问题。我认为这适用于 Win 7。要么我的记忆错了,要么这是 8.1 中的额外安全性。我会把你标记为答案,因为你让我得到了这个结果
  • “您是以管理员身份运行它吗?”这似乎是一种反常的扭曲。解决方案
猜你喜欢
  • 2012-08-29
  • 2012-07-20
  • 2020-07-14
  • 1970-01-01
  • 2020-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-17
相关资源
最近更新 更多