一千萬個為什麽

搜索

FileSystemObject的文件權限 - CScript.exe說一件事,Classic ASP說另一件事


我有一個經典的ASP頁面 - 用JScript編寫 - 使用Scripting.FileSystemObject將文件保存到網絡共享 - 而且它不起作用。 (“沒有權限”)

ASP頁面在IIS下使用Windows身份驗證運行,並啟用了模擬。

如果我通過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頁面中運行相同的代碼,則將Response.Write替換為WScript.Echo,我得到以下輸出:

MY_COMPUTER
dylan.beattie
MYDOMAIN
No

現在 - 我的理解是WScript.Network對象將檢索實際運行代碼的線程的當前安全憑證。如果這是正確的 - 那麽為什麽同一個域上的同一個用戶從CScript.exe到ASP獲得不同的結果?如果我的ASP代碼 以dylan.beattie運行,那為什麽我看不到網絡共享?如果以dylan.beattie身份運行,為什麽WScript.Network會認為它是?

最佳答案

你的問題很清楚。在當前的實現中,您只能模擬用戶而沒有委派。我不想重復斯蒂芬馬丁已經寫過的信息。我只想添加至少三個解決方案。斯蒂芬馬丁建議的經典授權方式只是一種方式。您可以在此處閱讀更多方法: http://msdn.microsoft。 COM/EN-US /庫/ ff647404.aspx#paght000023_delegation 。我看到了解決問題的三種實用方法:

  1. 將用戶的模擬令牌轉換為具有模擬委派級別或新主要令牌的令牌。您可以使用 DuplicateTokenDuplicateTokenEx 執行此操作。

  2. 使用 S4U2Self (請參閱 http ://msdn.microsoft.com/en-us/magazine/cc188757.aspx http://msdn.microsoft.com/en-us/library/ms998355.aspx )從一個簡單的.NET語句 WindowsIdentity接收舊令牌wi =新的WindowsIdentity(身份);

  3. 您可以訪問一個固定帳戶的其他服務器。它可以是IIS應用程序池帳戶上的計算機帳戶。它可以是另一個固定定義的帳戶,只能用於訪問文件系統。

了解運行IIS的服務器上的Windows Server版本以及域中Active Directory中的域功能級別非常重要(如果選擇域,則可以在“Active Directory域和信任”工具中看到此功能並選擇“提升域功能級別”)。了解IIS的應用程序池在哪個帳戶下運行也很有趣。

第一種和第三種方式將始終有效。第三種方式可能對您的環境和文件系統中的當前權限不利。第二個非常優雅。它允許控制從IIS訪問哪些服務器(文件服務器)。這種方式有一些限制,需要在Active Directory中完成一些工作。

因為您使用經典ASP,所以必須創建一個小的可編寫腳本的軟件組件來支持您的實現。

您更喜歡哪種方式?

UPDATED based on the question from comment: Because you use classic ASP you can not use a Win32 API directly, but you can write a small COM component in VB6 or in .NET which use APIs which you need. As an example you can use code from http://support.microsoft.com/kb/248187/en. But you should do some other things inside. So I explain now which Win32 API can help you to do everything what you need with tokens and impersonation.

首先是關於冒充的一個小解釋。一切都很容易。始終有一個主令牌運行該進程。對於任何線程,可以分配另一個令牌(線程令牌)。要做到這一點,需要有一個用戶 hUserToken 的令牌,並調用API ImpersonateLoggedOnUser(hUserToken);

要返回原始進程令牌(僅適用於當前線程),可以調用 RevertToSelf()函數。 IIS將收到用戶令牌並已為您模擬,因為您已配置了您的網站。要返回原始進程令牌,您應該在自定義COM組件中實現函數 RevertToSelf()的調用。也許,如果你不需要在ASP頁面中做更多的事情,那就足夠了,但我建議你在使用文件操作之前要更加小心並將當前用戶令牌保存在變量中。然後使用文件系統進行所有操作,最後將用戶令牌重新分配回當前線程。您可以使用 SetThreadToken(NULL,hUserToken); 為模擬分配模擬令牌。要提供(保存)當前線程令牌(在您的情況下為用戶令牌),您可以使用 OpenThreadToken API。它必須工作。

UPDATED 2: Probably the usage of RevertToSelf() function at the end of one ASP page would be already OK for you. The corresponding C# code can be so:

在“類庫”類型的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();
        }
    }
}

Check in project properties in "Build" part "Register for COM interop". In "Signing" part of the project check Sign the assembly and in "Choose a strong name key file" choose , then type any filename and password (or check off "protect my key..."). At the end you should modify a line from AssemblyInfo.cs in Properties part of the project:

[assembly: ComVisible (true)]

編譯此項目後,您將獲得兩個文件:LoginAdmin.dll和LoginAdmin.tlb。 DLL已在當前計算機上註冊。要在另一臺計算機上註冊,請使用 RegAsm.exe

要在ASP頁面上測試此COM DLL,您可以執行以下操作


<html><body>
    ");
       Response.Write("Current user's domain: ");Response.Write(objNet.UserDomain);Response.Write("
"); var objLoginAdmin = Server.CreateObject("LoginAdmin.UserImpersonate"); var isOK = objLoginAdmin.RevertToSelf(); if (isOK) Response.Write("RevertToSelf return true
"); else Response.Write("RevertToSelf return false
"); Response.Write("One more time after RevertToSelf()
"); Response.Write("Current user: ");Response.Write(objNet.UserName);Response.Write("
"); Response.Write("Current user's domain: ");Response.Write(objNet.UserDomain);Response.Write("
"); 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 

轉載註明原文: FileSystemObject的文件權限 - CScript.exe說一件事,Classic ASP說另一件事

猜你喜歡