客户端/服务器应用程序,如何在不将用户名/密码传输到远程系统的情况下,以域用户身份在远程系统上创建进程?

时间:2019-04-10 23:40:22

标签: c# kerberos windows-identity

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

我得到的最接近的信息似乎是我可以在计算机1上使用函数KerberosRequestorSecurityToken来生成kerberos票证,然后通过我的客户机/服务器代码将该byte []结果发送到计算机2,然后它应该能够对传递的byte [] kerberos票证调用KerberosReceiverSecurityToken。如果一切正常,则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;

1 个答案:

答案 0 :(得分:1)

第一段代码的来源在功能上是错误的。 SPN必须是接收票证的目标,而不是请求票证的用户。因此,您需要执行以下操作...

  1. 在AD中注册服务主体帐户(用户/计算机)。
  2. 将服务主体名称添加到foo/host.domain.com格式的帐户中,其中foo是您的服务名称,例如httphostmyapp
  3. 客户需要申请前往foo/host.domain.com的票证
  4. KerberosReceiverSecurityToken应该解析那个票据

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

因此,您需要使用DuplicateTokenEx将其转换为主要令牌,并且您实际上需要成为SYSTEM来这样做。

拥有主要令牌后,您就可以致电CreateProcessAsUser

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

另一种选择,也许是更安全,更容易的选择,而是以低特权用户身份启动工作进程,并告知 该进程要模拟。参见this answer for more information