代码之家  ›  专栏  ›  技术社区  ›  Dylan Beattie

文件系统对象的文件权限-cscript.exe说一件事,经典asp说另一件事

  •  6
  • Dylan Beattie  · 技术社区  · 15 年前

    我有一个用JScript编写的经典ASP页面,它使用scripting.filesystemobject将文件保存到网络共享中,但它不起作用。(许可被拒绝)

    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页的一部分相同,则用response.write替换wscript.echo,则会得到以下输出:

    MY_COMPUTER
    dylan.beattie
    MYDOMAIN
    No
    

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

    2 回复  |  直到 15 年前
        1
  •  4
  •   Peter Mortensen icecrime    15 年前

    你的问题很清楚。在当前的实现中,您只有模拟用户,没有委派。我不想重复斯蒂芬·马丁已经写的信息。我只想添加至少三个解决方案。史蒂芬·马丁建议的代表团的经典方式只是一种方式。您可以在这里阅读更多方法: http://msdn.microsoft.com/en-us/library/ff647404.aspx#paght000023_delegation . 我看到你解决问题的三种实际方法:

    1. 将用户的模拟令牌转换为具有模拟委派级别的令牌或新的主令牌。你可以这样做 DuplicateToken DuplicateTokenEx .

    2. 使用 S4U2自我 (见 http://msdn.microsoft.com/en-us/magazine/cc188757.aspx http://msdn.microsoft.com/en-us/library/ms998355.aspx )就一个简单的.NET语句从旧标记接收新标记 WindowsIdentity wi = new WindowsIdentity(identity);

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

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

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

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

    你喜欢哪种方式?

    更新的 基于注释中的问题:因为您使用的是经典的ASP,所以不能直接使用win32 API,但是您可以在vb6或.NET中编写一个小的COM组件,该组件使用您需要的API。例如,您可以使用 http://support.microsoft.com/kb/248187/en . 但是你应该在里面做些别的事情。因此,我现在解释哪些win32 API可以帮助您使用令牌和模拟完成所需的一切工作。

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

    要返回到原始进程令牌(仅限当前线程),可以调用 RevertToSelf() 功能。由于您已配置了网站,因此IIS将接收并已为您模拟用户的令牌。要返回到原始进程令牌,应该实现对函数的调用 ReloToSelf() 在自定义COM组件中。可能,如果您不需要在ASP页面中做更多的事情,这就足够了,但是我建议您在使用文件进行操作之前,更小心地将当前用户标记保存在变量中。然后使用文件系统执行所有操作,最后将用户令牌重新分配回当前线程。可以将模拟令牌分配给线程 SetThreadToken(NULL,hUserToken); . 要提供(保存)当前线程令牌(在您的情况下为用户令牌),可以使用 OpenThreadToken 应用程序编程接口。它必须工作。

    更新的 2:可能是使用 ReloToSelf() 功能 最后 一个ASP页面中的一个页面对您来说已经可以了。相应的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();
            }
        }
    }
    

    在“build”部分“register for com interop”中签入项目属性。在项目的“签名”部分,检查对程序集签名,并在“选择强名称密钥文件”中选择 <New...> ,然后键入任何文件名和密码(或选中“保护我的密钥…”)。最后,您应该在项目的属性部分修改assemblyinfo.cs中的一行:

    [assembly: ComVisible (true)]
    

    编译此项目后,您将得到两个文件:loginadmin.dll和loginadmin.tlb。DLL已在当前计算机上注册。如果在另一台计算机上注册,请使用 Reasas.EXE .

    要在ASP页上测试此COM DLL,可以执行以下操作

    <%@ 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 
    
        2
  •  4
  •   Stephen Martin    15 年前

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

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

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

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

    推荐文章