How to Start/Stop a Windows Service from an ASP.NET app - Security issues

前端 未结 6 1307
没有蜡笔的小新
没有蜡笔的小新 2020-12-04 18:33

Here\'s my Windows/.NET security stack:

  • A Windows Service running as LocalSystem on a Windows Server 2003 box.
  • A .NET 3.5 Website running on the same
相关标签:
6条回答
  • 2020-12-04 19:02

    This was a good question that intrigued me as well...

    So here is what I did to solve this problem:

    • Step 1: Create a Windows user account on the local machine with minimal rights.
    • Step 2: Give this user rights to start and stop the service via subinacl.exe
    • i.e. subinacl.exe /service WindowsServiceName /GRANT=PCNAME\TestUser=STOE
    • Dowload from : http://www.microsoft.com/en-za/download/details.aspx?id=23510
    • Step 3: Use Impersonation to impersonate the use created in Step 1 to start and stop the 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();
              }
      
          }
      }
      
    0 讨论(0)
  • 2020-12-04 19:07

    To give IIS permission to start/stop a particular service:

    • Download and install Subinacl.exe. (Be sure to get the latest version! Earlier versions distributed in some resource kits don't work!)
    • Issue a command similar to: subinacl /service {yourServiceName} /grant=IIS_WPG=F

    This grants full service control rights for that particular service to the built-in IIS_WPG group. (This works for IIS6 / Win2k3.) YMMV for newer versions of IIS.)

    0 讨论(0)
  • 2020-12-04 19:11

    Try adding this to your Web.Config.

    <identity impersonate="true"/>
    
    0 讨论(0)
  • 2020-12-04 19:13

    Update for IIS 8 (and maybe some slightly earlier versions)

    The usergroup IIS_WPG does not exist anymore. It has changed to IIS_IUSRS.

    Also, to start stop a service it is not neccesary to give full permissions (F). Permissions to start, stop and pause a service (TOP) should be enough. As such the command should be:

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

    Note that you need to point the command prompt (preferably elevated to run as administrator) to C:\Windows\System32 Folder before running this command.

    Also make sure that you have copied the subinacl.exe file to C:\Windows\System32 from the installation directory if there is an error.

    0 讨论(0)
  • 2020-12-04 19:19

    Just a hunch, but it does not appear to me the error is necessarily related to security. Did you give the service the same name on the production server?

    0 讨论(0)
  • 2020-12-04 19:20

    If your web application has the database and windows service can access it, you can just use the flag in the DB to restart the service. In the service, you can read this flag and restart if not busy etc. Only in case if you can modify the code of the service. If it's third party service you can create your own windows service and use database config to control (restart) services. It's the safe way and gives you much more flexibility and security.

    0 讨论(0)
提交回复
热议问题