Asp classic FileSystemObject-CScript.exe的文件权限说明了一件事,经典ASP说明了另一件事

Asp classic FileSystemObject-CScript.exe的文件权限说明了一件事,经典ASP说明了另一件事,asp-classic,permissions,wsh,filesystemobject,Asp Classic,Permissions,Wsh,Filesystemobject,我有一个用JScript编写的经典ASP页面,它使用Scripting.FileSystemObject将文件保存到网络共享,但它不起作用。(“拒绝许可”) ASP页正在IIS下使用Windows身份验证运行,并启用了模拟 如果我通过CScript.exe在本地运行以下代码块: var objNet = new ActiveXObject("WScript.Network"); WScript.Echo(objNet.ComputerName); WScript.Echo(objNet.User

我有一个用JScript编写的经典ASP页面,它使用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");
}
我得到(预期)输出:

如果我运行与.ASP页面相同的代码,将Response.Write替换为WScript.Echo,则会得到以下输出:

MY_COMPUTER
dylan.beattie
MYDOMAIN
No

现在-我的理解是WScript.Network对象将检索实际运行代码的线程的当前安全凭据。如果这是正确的-那么为什么同一个域上的同一个用户从CScript.exe和ASP获得不同的结果?如果我的ASP代码以dylan.beattie的身份运行,那么为什么我看不到网络共享?如果它不是以dylan.beattie的身份运行,为什么WScript.Network会认为它是?

在模拟下,您只能访问本地计算机上的安全资源,无法通过网络访问任何内容

在Windows上,当您作为模拟用户运行时,您是在所谓的网络令牌下运行的。此令牌具有本地计算机访问的用户凭据,但没有远程访问的凭据。因此,当您访问网络共享时,您实际上是以匿名用户的身份访问它

当您在桌面上运行进程(如CScript.exe)时,您是在交互式用户令牌下运行的。此令牌具有本地和远程访问的完整凭据,因此您可以访问网络共享


为了在模拟Windows用户时访问远程资源,必须使用委派而不是模拟。这将涉及对Active directory的一些更改,以允许计算机和/或域中的用户进行委派。这可能是一种安全风险,因此应仔细检查。

您的问题很清楚。在当前的实现中,您只模拟用户,没有委派。我不想重复斯蒂芬·马丁已经写过的信息。我只想添加至少三个解决方案。斯蒂芬·马丁(Stephen Martin)提出的经典授权方式只是一种方式。您可以在此处阅读更多方法:。我认为解决问题有三种切实可行的方法:

  • 将用户的模拟令牌转换为具有模拟委派级别的令牌或新的主令牌。您可以针对
    DuplicateToken
    DuplicateTokenEx
    执行此操作

  • 使用S4U2Self(请参阅和)从旧令牌接收一个简单的.NET语句的新令牌
    WindowsIdentity wi=new-WindowsIdentity(identity)

  • 您可以使用一个固定帐户访问另一台服务器。它可以是IIS应用程序池帐户上的计算机帐户。它可以是另一个只用于访问文件系统的固定定义帐户

  • 了解运行IIS的服务器上的Windows Server版本以及域在Active Directory中的域功能级别非常重要(如果选择域并选择“提升域功能级别”,则可在“Active Directory域和信任”工具中看到这一点)。了解IIS的应用程序池在哪个帐户下运行也很有趣

    第一种和第三种方法总是有效的。第三种方法可能对您的环境和文件系统中的当前权限有害。第二个非常优雅。它允许控制从IIS访问哪些服务器(文件服务器)。这种方式有一些限制,需要在Active Directory中完成一些工作

    因为您使用的是经典ASP,所以必须创建一个小的可编写脚本的软件组件来支持您的实现

    你喜欢哪种方式

    根据评论中的问题更新了:因为您使用的是经典ASP,所以不能直接使用Win32 API,但您可以在VB6或.NET中编写一个使用您需要的API的小型COM组件。例如,您可以使用中的代码。但是你应该在里面做一些其他的事情。因此,我现在解释一下哪个Win32 API可以帮助您使用令牌和模拟完成所需的一切

    首先是一个关于模仿的小解释。一切都很容易。进程运行时始终有一个主令牌。可以为任何线程分配另一个令牌(线程令牌)。要做到这一点,需要有一个用户
    hUserToken
    的令牌,并调用API
    ImpersonateLoggedOnUser(hUserToken)

    要返回到原始进程令牌(仅适用于当前线程),可以调用
    RevertToSelf()
    函数。用户的令牌将被IIS接收并已为您模拟,因为您已这样配置了网站。要返回到原始进程令牌,您应该在自定义COM组件中实现函数
    RevertToSelf()
    的调用。也许,如果您不需要在ASP页面中执行更多操作,这就足够了,但我建议您在对文件进行操作之前要更加小心,将当前用户令牌保存在一个变量中。然后使用文件系统执行所有操作,最后将用户令牌重新分配回当前线程。您可以针对
    SetThreadToken(NULL,hUserToken)将模拟令牌分配给线程。要提供(保存)当前线程令牌(在您的情况下为用户令牌),您可以使用
    OpenThreadToken
    API。它必须起作用

    更新2:可能在一个ASP页面的结尾使用
    RevertToSelf()
    函数,对您来说已经可以了。相应的C#代码可以是:

    在C#中创建一个名为
    LoginAdmin
    的“类库”类型的新项目。过去的
    MY_COMPUTER
    dylan.beattie
    MYDOMAIN
    No
    
    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();
            }
        }
    }
    
    [assembly: ComVisible (true)]
    
    <%@ 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>
    
    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