【问题标题】:Starting another process with elevation using different user credentials使用不同的用户凭据启动另一个具有提升的进程
【发布时间】:2012-04-09 23:51:44
【问题描述】:

我正在尝试从非提升进程启动提升进程,但我还需要为具有管理凭据的用户提供用户名和密码。我已经尝试了 "runas" 提升方法以及使用清单,但都产生了不同的错误。

例如,如果我这样做(不使用需要提升的清单):

ProcessStartInfo info = new ProcessStartInfo(path);

info.UseShellExecute = false;
info.UserName = username;
info.Password = securePwd;
info.Domain = "MyDomain";
info.Verb = "runas";

var proc = Process.Start(info);

进程在不显示 UAC 确认对话框的情况下启动,并且在尝试执行需要管理员权限的命令时失败(我只是尝试将测试文件写入 Program Files 目录)。

如果我向目标应用程序添加一个表明它需要提升的清单,那么我会收到一个 Win32Exception 说明该操作需要提升。

问题似乎是将UseShellExecute 设置为false(因为这两种方法都可以正常工作,但情况并非如此),但我必须将其设置为 false 才能在不同的用户帐户下启动该进程。

如何从非提升的进程启动提升的进程并手动提供用户名和密码?

BOUNTY EDIT:虽然不能要求用户输入管理员凭据,但 UAC 唠叨对话框是完全可以接受的。我不想在这里绕过 UAC。

【问题讨论】:

  • 对于那些可能好奇的人来说,这个应用程序是一个自动更新包的一部分,它将运行一个将为所有用户安装的 MSI。鉴于实际运行应用程序的用户很可能没有管理凭据(他们也不知道管理员的用户名和密码),我需要能够允许实际管理员提供这些凭据一次并在多个上运行此应用程序机器同时进行。
  • 我还需要考虑关闭 UAC 的场景。
  • 您的清单正在使用 requestedExecutionLevel,正如 here 所建议的那样,对吗?在我尝试诊断问题之前,我只是确保您为提示升级权限所做的一切都已解决。清单在 XP 中不起作用(请参阅链接文章),但在 Vista 中将起作用。
  • @MrGomez:是的,清单创建正确。如果我在没有指定用户的情况下启动它,它可以正常工作如果 UAC 处于打开状态(尽管我必须手动输入凭据,我必须避免),但如果我指定凭据,它将不允许提升过程。
  • 感谢您的回复和编辑。我添加了一个我相信对你有用的答案。最坏的情况,需要检查!

标签: .net security uac


【解决方案1】:

我很惊讶没有办法做到这一点,直到我找到了 Chris Jackson 的博客文章:

Why Can’t I Elevate My Application to Run As Administrator While Using CreateProcessWithLogonW?

您需要一个引导程序。一些可以让您转换到备用用户的进程,该用户可能负责运行 requireAdministrator 应用程序。所以,你可以设计这样的东西:

我们为什么不直接创建ShellExecuteWithLogonW API?我永远不会说永远,我们可能会在某个时候。但是今天,这个 API 的用例已经成为一种替代设计更优越的用例。

最常见的要求是编写本土软件部署软件的人,他们希望将凭据直接编码到应用程序中并提升自己的流程。这里真正的问题不是缺少 API,而是您的应用程序中编码了管理员凭据以供全世界阅读。

所以解决方案需要ShellExecute,它是唯一知道如何触发同意对话框的解决方案。

它提出了一个很好的观点:你已经用一个人的密码做什么了?

奖金聊天

Server Core 上没有 UAC,因为没有显示同意提示的窗口。

【讨论】:

  • 单个管理用户将提供网络管理员凭据,以便在他们选择安装更新时用于安装更新。这些凭据将安全地传递给客户端,客户端将使用它们来启动更新过程。我承认我没有考虑使用 middle 进程(使用管理员凭据启动)然后使用 ShellExecute 启动提升的进程。我会试一试。
  • 完美!使用使用指定凭据运行的中间进程,然后使用runas 启动另一个进程是完美的。
  • 我真的希望runas 不是提升流程的唯一方法;但你让它工作很好。现在我知道该怎么做了。实际上,您可以作为另一个用户重新启动自己的进程,并使用命令行参数告诉自己 ShellExecute 另一个人。或者以另一个用户身份启动另一个程序,并使用命令行参数告诉它以管理员身份重新启动自己。或者使用第三个应用程序。如果我需要“以另一个用户的身份运行我自己的程序”,我会以另一个用户的身份重新启动自己,然后runas 提升。
  • 这就是我正在做的。一个可执行文件启动了 3 次。
  • 虽然我完全同意这个答案提出的设计考虑和安全问题,但对于那些坚持这样做的人来说,有一个简单的方法:通过调用“cmd.exe /C”来启动你的进程如问题中指定的管理员凭据,其中您所需的可执行文件和任何命令行参数遵循 /C 选项。这将打开一个额外的 cmd 窗口(诚然不理想),并提示用户通过 UAC 对话框接受提升。
【解决方案2】:

ProcessStartInfo.Verb="runas" 仅适用于 windows Vista 及更高版本,因此您应该询问系统级别,而不是 XP 的提升。

我认为如果你选择ProcessStartInfo.Verb="runas",你不应该指定用户名和密码。

如果UAC是的,那么无论如何它都应该成功,这应该不是问题。

【讨论】:

  • 对不起,没有。你是对的,它只适用于 Vista 及更高版本,我必须对此进行测试,但我们当前的测试机器是 Windows 7。在关闭 UAC 的情况下,使用 "runas" 只会导致程序在作为非运行时失败行政人员。启用 UAC 后,它会提示输入管理员凭据。
【解决方案3】:

如果您正在创作 Windows Installer (MSI) 应用程序并使用 MSP 对其进行更新,那么 Windows Installer 会为您的场景提供内置支持:- 请查看 User Account Control (UAC) Patching

它的工作原理基本上是这样的:

  • 当您创作原始 MSI 时,您会生成一个证书,并将其公钥(或类似的东西)放入 MSI。
  • 目标机器的管理员在机器上安装 MSI。
  • 您创作更新 (MSP),并使用证书对其进行签名。
  • 目标计算机上的任何用户现在都可以安装更新 - Windows 安装程序将根据原始 MSI 中的公钥验证证书,如果是,则同意安装。我认为您根本不会收到 UAC 提示,但我不确定。

【讨论】:

  • 有趣;我可能需要对此进行调查。它与我当前的方法不太吻合(当前的存根应用程序完全卸载现有版本并出于各种不相关的原因安装新版本的新副本),但如果我不能,我可能会看看找到另一种解决方法。我目前的计划是使用更新服务,它可以在无人值守的情况下启动安装,并通过某种 IPC 向用户报告。
【解决方案4】:

根据 MSDN 文档:

当 UseShellExecute 为 false 时,您只能使用以下命令启动可执行文件 Process 对象。

我注意到您的声明 var proc = Process.Start(info); 没有使用 Process 作为类类型。

还要确保参数path 是可执行文件的完全限定路径。比如"c:\\directory\\contains\\process_to_be_started\\executable.exe"

根据 MSDN 文档,这很重要:

如果 UserName 和 Password 是,则必须设置 WorkingDirectory 属性 假如。如果未设置该属性,则默认工作目录为 %SYSTEMROOT%\system32。

我会尝试下面的代码以提升权限(具有管理员权限)运行目标进程。

ProcessStartInfo info = new ProcessStartInfo(path);

info.UseShellExecute = false;
info.UserName = username;
info.Password = securePwd;
info.Domain = "MyDomain";
info.Verb = "runas";
info.WorkingDirectory = "c:\\directory\\contains\\process_to_be_started"

'var proc = Process.Start(info);

Process proc = Process.Start(info);

【讨论】:

  • 变量声明是var还是Process都没有区别
  • @Onkelborg 是正确的; var 只是隐式键入变量。它的编译就像我将它声明为 Process 一样。除此之外,我已经完全符合这条道路了。
【解决方案5】:

From MSDN:

您不能提升已在运行的进程。因此,你应该 将您的应用程序重构为管理员和非管理员操作 - 以正常权限运行默认应用程序并启动 每个管理操作的另一个提升的进程。

假设您是request administrator rights from the outset on the processes that require them,让我们一起努力。根据您提供的上下文:

问题似乎是将UseShellExecute 设置为false(因为两者 如果不是这种情况,方法可以正常工作),但我必须设置它 为 false 以在不同的用户下启动进程 帐户。

正如你提到的,正如the documentation for UseShellExecute 中所述:

如果 UserName 属性不是 Nothing,则 UseShellExecute 必须为 false 或空字符串,否则将抛出 InvalidOperationException 当 Process.Start(ProcessStartInfo) 方法被调用时。

我们现在知道您是在直接执行程序,而不是通过使用 shell。这是有价值的信息。

回溯文档,the docs for ProcessStartInfo 带有以下安全说明:

该类包含类级别的链接需求,适用于 所有成员。当直接调用者时抛出 SecurityException 没有完全信任权限。有关安全性的详细信息 需求,见Link Demands

所以,您没有正确的链接需求。在尝试解决您的权限问题时,您无意中创建了另一个权限问题。

结果是你需要用正确的Security Demand来装饰你的调用方法,它应该是FullTrust。您可以在代码中执行此操作 declarativelyimperatively

(Additional reading)

【讨论】:

  • 很有趣,但是哪个有需求?并且文档似乎暗示无论使用如何,安全性都是相同的;为什么UseShellExecute = false 会失败,而= true 不会失败?
  • 请原谅我的简洁。根据权限范围 ([PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]) 和文档,您需要 FullTrust。至于为什么在UseShellExecute = false时会失败,注意这里区分你的代码是ShellExecute还是CreateProcess运行的; ShellExecute 将为您提供完全不同的安全链和一组修复程序。有关更多信息,我建议您查看 here 并在调试器中运行您当前的代码。
  • 我明白了;我不认为我第一次读正确。不幸的是,我尝试使用该属性装饰方法和类,但行为没有改变。
  • @AdamRobinson 不用担心。当你命令式地尝试这个时会发生什么,比如CustomPermission MyPermission = new CustomPermission(PermissionState.Unrestricted); MyPermission.Demand();
  • @AdamRobinson 哦,好吧。张开嘴,插入脚。要尝试的最后一件事是,由于 FullTrust 需求,您将需要管理员权限才能使用所需的用户和密码凭据,即在清单文件 as here 中包含 requestedExecutionLevel,以确保安全如上所述,需求到位。我找不到任何其他适用的建议。
猜你喜欢
  • 1970-01-01
  • 2019-12-16
  • 1970-01-01
  • 1970-01-01
  • 2014-08-20
  • 2010-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多