6

Scripting.FileSystemObject を使用してファイルをネットワーク共有に保存する、JScript で記述された従来の ASP ページがありますが、機能していません。("アクセス拒否")

ASP ページは、偽装を有効にして、Windows 認証を使用して IIS で実行されています。

CScript.exe を介して次のコード ブロックをローカルで実行すると、次のようになります。

var objNet = new ActiveXObject("WScript.Network");
WScript.Echo(objNet.ComputerName);
WScript.Echo(objNet.UserName);
WScript.Echo(objNet.UserDomain);

var fso = new ActiveXObject("Scripting.FileSystemObject");
var path = "\\\\myserver\\my_share\\some_path";
if (fso.FolderExists(path)) {
    WScript.Echo("Yes");
} else {
    WScript.Echo("No");
}

(期待される)出力が得られます:

MY_COMPUTER
dylan.beattie
MYDOMAIN
Yes

.ASP ページの一部として同じコードを実行すると、WScript.Echo を Response.Write に置き換えて、次の出力が得られます。

MY_COMPUTER
dylan.beattie
MYDOMAIN
No

さて、私の理解では、WScript.Network オブジェクトは、実際にコードを実行しているスレッドの現在のセキュリティ資格情報を取得します。これが正しければ、同じドメインの同じユーザーが、CScript.exe と ASP で異なる結果を得るのはなぜですか? ASP コードdylan.beattie として実行されている場合、ネットワーク共有が表示されないのはなぜですか? また、それが dylan.beattie として実行されていない場合、なぜ WScript.Network はそうであると判断するのでしょうか?

4

2 に答える 2

4

偽装では、ローカル コンピューター上の保護可能なリソースにしかアクセスできず、ネットワーク経由では何にもアクセスできません。

Windows では、偽装ユーザーとして実行している場合、ネットワーク トークンと呼ばれるもので実行しています。このトークンには、ローカル コンピューター アクセス用のユーザーの資格情報がありますが、リモート アクセス用の資格情報はありません。したがって、ネットワーク共有にアクセスするときは、実際には匿名ユーザーとしてアクセスしています。

デスクトップでプロセス (CScript.exe など) を実行しているときは、インタラクティブ ユーザー トークンで実行しています。このトークンには、ローカル アクセスとリモート アクセスの両方の完全な資格情報が含まれているため、ネットワーク共有にアクセスできます。

Windows ユーザーを偽装しながらリモート リソースにアクセスするには、偽装ではなく委任を使用する必要があります。これには、ドメイン内のコンピューターおよび/またはユーザーの委任を許可するために、Active Directory にいくつかの変更が含まれます。これはセキュリティ リスクになる可能性があるため、慎重に確認する必要があります。

于 2010-05-10T10:19:18.623 に答える
4

あなたの問題は明らかです。現在の実装では、ユーザーの偽装のみがあり、委任はありません。Stephen Martin によって既に書かれた情報を繰り返したくありません。少なくとも 3 つのソリューションを追加したいだけです。Stephen Martin が提案する委任の古典的な方法は、1 つの方法にすぎません。ここでいくつかの方法を読むことができます: http://msdn.microsoft.com/en-us/library/ff647404.aspx#paght000023_delegation。問題を解決するための 3 つの実用的な方法があります。

  1. ユーザーの偽装トークンを委任レベルの偽装のトークンまたは新しいプライマリ トークンに変換します。DuplicateTokenまたはに関してこれを行うことができますDuplicateTokenEx

  2. S4U2Self ( http://msdn.microsoft.com/en-us/magazine/cc188757.aspxおよびhttp://msdn.microsoft.com/en-us/library/ms998355.aspxを参照) を使用して、新しいトークンを受け取ります。 1 つの単純な .NET ステートメントに関する古いものWindowsIdentity wi = new WindowsIdentity(identity);

  3. 1 つの固定アカウントに関して、別のサーバーにアクセスできます。IIS のアプリケーション プールのアカウントのコンピューター アカウントにすることができます。これは、ファイル システムへのアクセスにのみ使用する別の固定定義アカウントにすることができます。

IIS が実行されているサーバーにある Windows Server のバージョンと、ドメインの Active Directory にあるドメイン機能レベルを把握しておくことが重要です (ドメインを選択すると、「Active Directory Domain and Trusts」ツールでこれが表示されます)。をクリックし、[ドメインの機能レベルを上げる] を選択します)。また、IIS のアプリケーション プールがどのアカウントで実行されているかを知ることも興味深いことです。

最初と 3 番目の方法は常に機能します。3 番目の方法は、環境やファイル システムの現在のアクセス許可に悪影響を与える可能性があります。2枚目はとてもエレガントです。IIS からアクセスするサーバー (ファイル サーバー) を制御できます。この方法にはいくつかの制限があり、Active Directory でいくつかの作業を行う必要があります。

従来の ASP を使用しているため、実装をサポートするために小さなスクリプト可能なソフトウェア コンポーネントを作成する必要があります。

あなたはどちらの方法を好みますか?

コメントからの質問に基づいて更新: 従来の ASP を使用しているため、Win32 API を直接使用することはできませんが、必要な API を使用する VB6 または .NET で小さな COM コンポーネントを作成できます例として、 http://support.microsoft.com/kb/248187/enのコードを使用できます。ただし、内部で他のことを行う必要があります。そこで、トークンと偽装で必要なことをすべて行うのにどの Win32 API が役立つかを説明します。

まず、なりすましについて簡単に説明します。すべてが非常に簡単に機能します。プロセスが実行されるプライマリ トークンは常に 1 つです。どのスレッドにも、別のトークン (スレッド トークン) を割り当てることができます。これを行うには、ユーザーのトークンを取得してhUserTokenAPI を呼び出す必要がありますImpersonateLoggedOnUser(hUserToken);

元のプロセス トークンに戻るには (現在のスレッドのみ)、RevertToSelf()関数を呼び出すことができます。Web サイトをそのように構成したため、ユーザーのトークンが IIS によって受信され、既に偽装されます。元のプロセス トークンに戻るにはRevertToSelf()、カスタム COM コンポーネントで関数の呼び出しを実装する必要があります。おそらく、ASP ページで何もする必要がなければそれで十分ですが、ファイルを操作する前に現在のユーザーのトークンを変数に保存することをお勧めします。次に、ファイル システムですべての操作を行い、最後にユーザー トークンを現在のスレッドに再割り当てします。に関して、偽装トークンをスレッドに割り当てることができますSetThreadToken(NULL,hUserToken);。現在のスレッドトークン(あなたの場合はユーザートークン)を与える(保存する)には、OpenThreadTokenAPIを使用できます。それはうまくいくはずです。

更新2: おそらく、 1 つの ASP ページの最後RevertToSelf()での関数の使用は、既に問題ないでしょう。対応する C# コードは次のようになります。

という名前の「クラス ライブラリ」タイプの C# で新しいプロジェクトを作成しますLoginAdmin。内部に次のコードを貼り付けます

using System;
using System.Runtime.InteropServices;

namespace LoginAdmin {
    [InterfaceTypeAttribute (ComInterfaceType.InterfaceIsDual)]
    public interface IUserImpersonate {
        [DispId(1)]
        bool RevertToSelf ();
    }

    internal static class NativeMethods {
        [DllImport ("advapi32.dll", SetLastError = true)]
        internal static extern bool RevertToSelf ();
    }

    [ClassInterface (ClassInterfaceType.AutoDual)]
    public class UserImpersonate : IUserImpersonate {
        public UserImpersonate () { }

        public bool RevertToSelf () {
            return NativeMethods.RevertToSelf();
        }
    }
}

「ビルド」部分の「COM相互運用の登録」でプロジェクトのプロパティをチェックインします。プロジェクトの "Signing" 部分で Sign the assembly をチェックし、"Choose a strong name key file" で を選択<New...>し、任意のファイル名とパスワードを入力します (または "protect my key..." をオフにします)。最後に、プロジェクトのプロパティ部分で AssemblyInfo.cs の行を変更する必要があります。

[assembly: ComVisible (true)]

このプロジェクトをコンパイルすると、LoginAdmin.dll と LoginAdmin.tlb の 2 つのファイルが得られます。DLL は、現在のコンピューターに既に登録されています。登録するには、他のコンピューターでRegAsm.exeを使用します。

この COM DLL を ASP ページでテストするには、次のようにします。

<%@ Language="javascript" %>
<html><body>
    <% var objNet = Server.CreateObject("WScript.Network");
       Response.Write("Current user: ");Response.Write(objNet.UserName);Response.Write("<br/>");
       Response.Write("Current user's domain: ");Response.Write(objNet.UserDomain);Response.Write("<br/>");

       var objLoginAdmin = Server.CreateObject("LoginAdmin.UserImpersonate");
       var isOK = objLoginAdmin.RevertToSelf();
       if (isOK)
              Response.Write("RevertToSelf return true<br/>");
       else
              Response.Write("RevertToSelf return false<br/>");
       Response.Write("One more time after RevertToSelf()<br/>");
       Response.Write("Current user: ");Response.Write(objNet.UserName);Response.Write("<br/>");
       Response.Write("Current user's domain: ");Response.Write(objNet.UserDomain);Response.Write("<br/>");

       var fso = Server.CreateObject("Scripting.FileSystemObject");
       var path = "\\\\mk01\\C\\Oleg";
       if (fso.FolderExists(path)) {
          Response.Write("Yes");
       } else {
          Response.Write("No");
       }%>
</body></html>

IIS アプリケーション プールの実行に使用されるアカウントが、対応するネットワーク共有にアクセスできる場合、出力は次のようになります。

Current user: Oleg
Current user's domain: WORKGROUP
RevertToSelf return true
One more time after RevertToSelf()
Current user: DefaultAppPool
Current user's domain: WORKGROUP
Yes 
于 2010-05-10T14:34:11.663 に答える