首页 > 解决方案 > 客户端/服务器应用程序,如何以域用户的身份在远程系统上创建进程,而不将该用户的用户名/密码传输到远程系统?

问题描述

我有两个系统都运行我的 C# 客户端/服务器软件代码。我想从计算机 1 创建一个进程作为计算机 2 上的给定 Active Directory 域用户,而不必让我的客户端/服务器软件将 AD 用户的纯文本用户名和密码从计算机 1 发送到计算机 2。

我得到的最接近的似乎是我可以使用计算机 1 上的函数 KerberosRequestorSecurityToken 生成一个 kerberos 票证,然后通过我的客户端/服务器代码将该字节 [] 结果发送到计算机 2,然后它应该能够调用 KerberosReceiverSecurityToken 反对已通过的 byte[] kerberos 票证。如果一切正常,那么 KerberosReceiverSecurityToken 将具有 WindowsIdentity 属性,然后我可以使用该属性在计算机 2 上创建一个进程,用户帐户最初通过 KerberosRequestorSecurityToken 流在计算机 1 上指定。

我需要使用要模拟的现有域用户帐户与注册服务帐户 SPN。这是我最初发布问题时没有提及的问题的症结所在。

我似乎无法让它工作,但更多所以我什至不知道这是否真的可能 - 例如,这些 API 是否应该允许我做我想做的事?

用于生成 kerberos 票证的计算机 1 代码。byte[] 结果通过我的客户端/服务器应用程序发送到计算机 2。

public static byte[] GetRequestToken(string userName, string password, string domain)
{
    using (var domainContext = new PrincipalContext(ContextType.Domain, domain))
    {
        using (var foundUser = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userName))
        {
            Console.WriteLine("User Principal name" + UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userName).UserPrincipalName);
            string spn = UserPrincipal.FindByIdentity(domainContext, IdentityType.SamAccountName, userName).UserPrincipalName;
            KerberosSecurityTokenProvider k1 = new KerberosSecurityTokenProvider(spn, TokenImpersonationLevel.Impersonation, new NetworkCredential(userName, password, domain));
            KerberosRequestorSecurityToken T1 = k1.GetToken(TimeSpan.FromMinutes(1)) as KerberosRequestorSecurityToken;
            var req = T1.GetRequest();
            return req;
        }
    }
}

计算机 2 获取生成的 byte[] kerberos 票证并尝试接收它以访问 WindowsIdentity,但它会引发异常登录无效。

KerberosReceiverSecurityToken receiverToken = new KerberosReceiverSecurityToken(requestToken);
byte[] receiverTokenTicket = receiverToken.GetRequest();

//Identity for impersonation
var impersonatedIdentity = receiverToken.WindowsIdentity;

标签: c#kerberoswindows-identity

解决方案


第一个代码块的来源在功能上是错误的。SPN 必须是接收票证的目标,而不是请求票证的用户。所以你需要做以下事情......

  1. 在 AD 中注册服务主体帐户(用户/计算机)。
  2. 将服务主体名称添加到该帐户,foo/host.domain.com其中 foo 是您的服务名称,例如httpor host、 or myapp
  3. 客户需要申请一张票到foo/host.domain.com
  4. KerberosReceiverSecurityToken应该解析那张

现在你有一个不同模拟级别的身份。该模拟级别决定了您是否可以以该用户身份启动进程。碰巧......你不能,因为这不是 Windows 安全的工作方式。因为您正在模拟用户,所以您有一个模拟 NT 令牌,而您需要一个主 NT 令牌来启动进程。

因此,您需要使用DuplicateTokenEx将其转换为主令牌,并且您实际上需要 SYSTEM 才能做到这一点。

获得主令牌后,您可以调用CreateProcessAsUser

此时,您可能已经以用户身份启动了该过程,但它没有任何凭据来访问其他网络属性,例如网络共享或 Web 服务。为此,您可以在服务主体上为任何下游服务启用约束委派。

另一种可能更安全、更容易的选择是作为低权限用户启动工作进程并告诉进程进行模拟。有关更多信息,请参阅此答案


推荐阅读