15

这是我的 Windows/.NET 安全堆栈:

  • 在 Windows Server 2003 机器上作为 LocalSystem 运行的 Windows 服务。
  • 一个 .NET 3.5 网站在同一个盒子上运行,在“默认”生产服务器 IIS 设置下(所以可能是 NETWORKSERVICE 用户?)

在我的默认 VS2008 DEV 环境中,我有一个方法,它从 ASP.NET 应用程序中调用,效果很好:

private static void StopStartReminderService() {

    ServiceController svcController = new ServiceController("eTimeSheetReminderService");

    if (svcController != null) {
        try {
            svcController.Stop();
            svcController.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(10));
            svcController.Start();
        } catch (Exception ex) {
            General.ErrorHandling.LogError(ex);
        }
    }
}

当我在生产服务器上运行它时,我从 ServiceController 收到以下错误:

来源:System.ServiceProcess -> System.ServiceProcess.ServiceController -> IntPtr GetServiceHandle(Int32) -> System.InvalidOperationException 消息:无法在计算机“.”上打开 eTimeSheetReminderService 服务。

为什么会发生这种情况,我该如何解决?

编辑:

答案如下,主要在评论中,但要澄清:

  1. 该问题与安全相关,并且由于 NETWORKSERVICE 帐户没有足够的权限来启动/停止服务
  2. 我创建了一个本地用户帐户,并将其添加到 PowerUsers 组(该组几乎具有管理员权限)
  3. 我不希望我的整个 Web 应用程序一直模拟那个用户,所以我只在我操作服务的方法中模拟。我通过使用以下资源来帮助我在代码中做到这一点:

MS KB文章this,只是为了更好地理解

注意:我不通过 web.config 进行模拟,而是在代码中进行。请参阅上面的 MS 知识库文章。

4

6 回答 6

14

授予 IIS 启动/停止特定服务的权限:

  • 下载并安装Subinacl.exe。(一定要获取最新版本!部分资源包中分发的早期版本不起作用!
  • 发出类似于以下的命令: subinacl /service {yourServiceName} /grant=IIS_WPG=F

这将对该特定服务的完整服务控制权限授予内置 IIS_WPG 组。(这适用于 IIS6 / Win2k3。)YMMV 用于更新版本的 IIS。)

于 2012-05-03T01:14:04.793 回答
6

尝试将此添加到您的 Web.Config。

<identity impersonate="true"/>
于 2009-05-04T03:04:47.257 回答
1

这是一个很好的问题,也引起了我的兴趣......

所以这是我为解决这个问题所做的:

  • 第 1 步:在本地计算机上创建一个具有最低权限的 Windows 用户帐户。
  • 第 2 步:授予此用户通过 subinacl.exe 启动和停止服务的权限
  • 即 subinacl.exe /service WindowsServiceName /GRANT=PCNAME\TestUser=STOE
  • 下载地址:http : //www.microsoft.com/en-za/download/details.aspx?id= 23510
  • 第3步:使用Impersonation模拟第1步中创建的使用来启动和停止Service

    public const int LOGON32_PROVIDER_DEFAULT = 0;
    
    WindowsImpersonationContext _impersonationContext;
    
    [DllImport("advapi32.dll")]
    // ReSharper disable once MemberCanBePrivate.Global
    public static extern int LogonUserA(String lpszUserName,
        String lpszDomain,
        String lpszPassword,
        int dwLogonType,
        int dwLogonProvider,
        ref IntPtr phToken);
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    // ReSharper disable once MemberCanBePrivate.Global
    public static extern int DuplicateToken(IntPtr hToken,
        int impersonationLevel,
        ref IntPtr hNewToken);
    
    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    // ReSharper disable once MemberCanBePrivate.Global
    public static extern bool RevertToSelf();
    
    [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
    // ReSharper disable once MemberCanBePrivate.Global
    public static extern bool CloseHandle(IntPtr handle);
    
    private bool _impersonate;
    
    public bool ImpersonateValidUser(String userName, String domain, String password)
    {
        IntPtr token = IntPtr.Zero;
        IntPtr tokenDuplicate = IntPtr.Zero;
    
        if (RevertToSelf())
        {
            if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE,
                LOGON32_PROVIDER_DEFAULT, ref token) != 0)
            {
                if (DuplicateToken(token, 2, ref tokenDuplicate) != 0)
                {
                    var tempWindowsIdentity = new WindowsIdentity(tokenDuplicate);
                    _impersonationContext = tempWindowsIdentity.Impersonate();
                    if (_impersonationContext != null)
                    {
                        CloseHandle(token);
                        CloseHandle(tokenDuplicate);
                        _impersonate = true;
                        return true;
                    }
                }
            }
        }
        if (token != IntPtr.Zero)
            CloseHandle(token);
        if (tokenDuplicate != IntPtr.Zero)
            CloseHandle(tokenDuplicate);
        _impersonate = false;
        return false;
    }
    
    #region Implementation of IDisposable
    
    
    
    
    #endregion
    
    #region Implementation of IDisposable
    
    private void Dispose(bool dispose)
    {
        if (dispose)
        {
            if (_impersonate)
                _impersonationContext.Undo();
            _impersonationContext.Dispose();
        }
    }
    
    public void Dispose()
    {
        Dispose(true);
    }
    #endregion
    
    public static void StartStopService(bool startService, string serviceName)
    {
        using (var impersonateClass = new Impersonation())
        {
            impersonateClass.ImpersonateValidUser(Settings.Default.LocalUsername, Settings.Default.Domain, Settings.Default.Password);
            using (var sc = new ServiceController(serviceName))
            {
                if (startService)
                    sc.Start();
                else if (sc.CanStop)
                    sc.Stop();
            }
    
        }
    }
    
于 2014-10-13T10:05:10.960 回答
1

IIS 8 的更新(可能还有一些稍早的版本)

用户组IIS_WPG不再存在。它已更改为IIS_IUSRS

此外,要开始停止服务,无需授予完全权限 (F)。启动、停止和暂停服务 (TOP) 的权限应该足够了。因此,命令应该是:

subinacl /service {yourServiceName} /grant=IIS_IUSRS=TOP

请注意,在运行此命令之前,您需要将命令提示符(最好提升为以管理员身份运行)指向C:\Windows\System32文件夹。

C:\Windows\System32如果出现错误,还请确保您已将 subinacl.exe 文件从安装目录复制到 。

于 2017-07-14T04:09:33.173 回答
0

只是一种预感,但在我看来,错误不一定与安全有关。您是否在生产服务器上为该服务提供了相同的名称?

于 2009-05-04T01:55:35.753 回答
0

如果您的 web 应用程序有数据库并且 windows 服务可以访问它,您可以使用数据库中的标志来重新启动服务。在服务中,您可以读取此标志并在不忙时重新启动等。仅在您可以修改服务代码的情况下。如果是第三方服务,您可以创建自己的 Windows 服务并使用数据库配置来控制(重新启动)服务。这是安全的方式,并为您提供更多的灵活性和安全性。

于 2016-10-07T15:57:59.037 回答