15

これが私の Windows/.NET セキュリティ スタックです。

  • Windows Server 2003 ボックスで LocalSystem として実行されている Windows サービス。
  • 「デフォルト」の実動サーバーIIS設定の下で、同じボックスで実行されている.NET 3.5 Webサイト(おそらくNETWORKSERVICEユーザーとして?)

デフォルトの VS2008 DEV 環境では、ASP.NET アプリから呼び出される次の 1 つのメソッドがあり、正常に動作します。

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 の記事とこれ

注: web.config を介して偽装するのではなく、コードで実行します。上記の MS KB 記事を参照してください。

4

6 に答える 6

14

IIS に特定のサービスを開始/停止する権限を与えるには:

  • Subinacl.exeをダウンロードしてインストールします。(必ず最新バージョンを入手してください! 一部のリソース キットで配布されている以前のバージョンは動作しません! )
  • 次のようなコマンドを発行します。 subinacl /service {yourServiceName} /grant=IIS_WPG=F

これにより、その特定のサービスに対する完全なサービス コントロール権限が、組み込みの IIS_WPG グループに付与されます。(これは IIS6 / Win2k3 で機能します。) IIS の新しいバージョンの YMMV。)

于 2012-05-03T01:14:04.793 に答える
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: 偽装を使用して、ステップ 1 で作成したユーザーを偽装してサービスを開始および停止する

    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 に答える
0

ただの予感ですが、エラーが必ずしもセキュリティに関連しているとは思えません。本番サーバーでサービスに同じ名前を付けましたか?

于 2009-05-04T01:55:35.753 に答える