【问题标题】:Unable to reference UNC paths while using wscript.shell from an ASP script?在 ASP 脚本中使用 wscript.shell 时无法引用 UNC 路径?
【发布时间】:2023-08-12 15:07:02
【问题描述】:

我在使用 wscript.shell 对象通过 ASP 脚本从命令行执行命令时遇到问题。

这是我的代码:

inPath = server.mappath("/connect/dev_f_fusion3/video/6EA63679C27E48538D79F7C7295201CF/6EA63679C27E48538D79F7C7295201CF.mov")
outPath = server.mappath("/connect/dev_f_fusion3/video/6EA63679C27E48538D79F7C7295201CF\6EA63679C27E48538D79F7C7295201CF.flv"
outPath = "\\webdev2\SVC\streams\dev_f_fusion3\6EA63679C27E48538D79F7C7295201CF.flv"

dim cmd
dim wshell
dim wffm

cmd = """C:\Program Files\ffmpeg\ffmpeg.exe"" -i """ & inPath & """ -ar ""22050"" -ab ""32"" -f ""flv"" -s ""320x240"" """ & outPath & """"
set wshell  = server.createobject("wscript.shell")
set wffm = wshell.exec(cmd)

set wffm = nothing
set wshell = nothing

如您所见,我已经定义了两次变量 outPath 作为示例,以帮助我。第一个 outPath 分配 wscript.shell 对象执行得很好,但是,第二个 outPath 分配失败,让我相信它与我指定为 outPath 的 UNC 路径有关。

是否不允许 wscript.shell 对象访问 UNC 路径?如果是这样,我可以在哪里更改它以允许它们?

感谢您的帮助!

【问题讨论】:

  • 您是否检查过运行脚本的用户是否有权访问该路径?
  • @Tchami:是的,运行脚本的用户确实有权访问该路径。

标签: vbscript permissions asp-classic wsh


【解决方案1】:

听起来这里有两个潜在的问题来源: 1. 与启动新进程和让该进程访问 UNC 共享相关的问题 2. 是否使用新进程访问UNC共享的权限相关问题

我将从测试 #2 开始,检查您的站点是否可以在不启动新进程的情况下从远程共享读取文件。例如:

<%
dim filesys, filetxt
Const ForReading = 1, ForWriting = 2, ForAppending = 8 
Set filesys = CreateObject("Scripting.FileSystemObject")
Set filetxt = filesys.OpenTextFile("\\webdev2\SVC\streams\dev_f_fusion3\testfile.txt", ForReading, True) 
Response.Write (filetxt.ReadAll())
filetxt.Close 
%> 

如果失败,那么您的问题可能比较容易解决:您的网站无权访问远程共享。要解决此问题,最简单的方法是使用匿名身份验证并选择有权访问共享的匿名用户。这是tutorial 解释如何执行此操作。确保按照教程的建议禁用集成 Windows 身份验证!

还要确保您在处理和转义转换为 EXE 路径的用户输入时非常小心,因为您真的不希望恶意访问者能够在您的网络上运行任意代码!理想情况下,您永远不会直接基于用户输入创建执行路径或命令行参数的任何部分,而只是间接创建(例如,使用用户输入在数据库中查找已知安全的文件名,然后使用该数据库结果在你的道路上)。

还有其他方法(域用户下的匿名身份验证除外)启用远程访问,包括委托、通过 HTTPS 使用基本身份验证等。如果您不能使用匿名身份验证,请告诉我更多详细信息,我可以帮助您找出正确的替代方案。

但是,如果上面的文件访问测试成功,您的问题就更复杂了——这意味着在 IIS 进程内运行的代码具有正确的访问权限,但衍生的进程不会继承访问远程资源的能力。

更新:根据您在下面的评论,您已诊断出问题在于生成的进程是在错误的用户帐户下启动的。这可以通过直接调用一些 Win32 API 来解决,并且也有 .NET 解决方案,但除非您在 VBScript 之外感到很自在,否则您现在可能不想承担更多。

您能否将远程计算机上的文件复制到本地计算机上的临时文件中,然后运行 ​​FFMPEG.EXE,然后(如果需要)将更改保存回远程服务器,最后删除临时文件?

如果你能做到这一点,它将避免这个线程中描述的问题,将更容易在你的 ASP 代码中发现其他问题(例如网络故障)而不是隐藏在 FFMPEG.EXE 中,它甚至可以提高性能取决于 FFMPEG.EXE 处理远程文件访问的效率。

这里有一些用于将远程文件复制到临时本地位置的代码。警告,下面可能有一些拼写错误,因为我将一些示例粘在一起来创建它,并且没有时间自己测试它。

<%
dim filesys, filetxt
Const ForReading = 1, ForWriting = 2, ForAppending = 8 
Set filesys = CreateObject("Scripting.FileSystemObject")

Const TemporaryFolder = 2
Dim tfolder, tname, tfile
Set tfolder = fso.GetSpecialFolder(TemporaryFolder)
tname = tFolder & "/" & fso.GetTempName

Dim remoteFilename
remoteFilename = "\\webdev2\SVC\streams\dev_f_fusion3\testfile.txt"

Const OverwriteExisting = True
filesys.CopyFile  remoteFilename, tName, OverwriteExisting    
%> 

我相信这种本地复制方法将为您提供最佳的可靠性和可能的​​最佳性能,因为通过网络连接复制整个文件通常比一次读取一个块更快。如果最有可能失败的操作(网络文件访问)发生在您的代码中而不是其他人的代码中,那么您的错误处理和调试也会更容易。

但是,如果您确信需要使用 UNC 访问权限调用您的 EXE,那么最好的办法是使用 C++、C# 或 VB 构建一个 COM 组件,以取代 Wsh.Shell 作为您的进程启动器。我建议使用 .NET 语言而不是本机 C++ 来构建组件,因为调用会容易得多。如果您在 .NET 中执行此操作,您将需要使用 System.Diagnostics.Process 类来启动您的进程,使用 ProcessStartInfo 类来指定要使用的用户名/密码。

您也可以尝试使用 WNetAddConnection2 创建连接,然后使用 CreateProcess 或类似的 Win32 API(或其 .NET 等效项)启动您的进程,但您可能需要尝试找到正确的参数以采用。

换句话说,构建这个包装器是一个非常困难的问题。您最好的选择可能是您当前的解决方法。

【讨论】:

  • @Justin:感谢您的回复。我已经知道权限都是按顺序设置的域用户为 asp 页面运行设置的。我可以通过同一页面上的文件系统对象访问共享。除了他们选择通过表单上传的文件之外,我尝试访问的路径绝不会受到用户输入的影响,因此我认为我的基础已经涵盖在那里。我认为这与您的#1 猜测有关。进程 ffmpeg.exe 的执行是使用其他一些无权访问共享的用户帐户启动的。不过仍在调查问题。
  • @Justin:使用@Mike 推荐的Process Monitor 工具,我能够准确地找出问题所在。在我的代码中启动的 ffmpeg.exe 进程作为 NT AUTHORITY\NETWORK SERVICE 执行,它无权访问远程服务器。我在进程监视器中遇到的错误是对远程服务器路径的创建文件调用被拒绝访问。我不确定如何解决这个问题。似乎该过程正在自动启动,因为在站点运行的 AppPool 中设置了身份的用户。不过我不想更改 AppPool 中的 ID。
  • @Ryan - 不幸的是,看起来这个问题很难单独使用 VBScript 来解决。请参阅上面我的更新答案。我的建议:考虑将文件从远程服务器复制到本地临时文件并在本地进行操作。您的其他选择更难,而且可能更慢且更不可靠。
  • @Justin:这就是我同时解决问题的方法。不是真正的修复,而是一种解决方法。我拥有完整的服务器访问权限,因此只要您能告诉我如何解决问题,我就可以执行不仅仅需要 VBScript 的修复。
  • @Ryan - 经过一番思考,我相信您当前的解决方法实际上是最好的解决方案。即使您解决了上述安全挑战,从单独的 EXE(尤其是您无法从源代码轻松调试的 EXE)访问网络文件也可能会造成麻烦。例如,来自断开连接或新安全问题的错误消息可能不清楚。此外,未明确设计用于网络文件访问的应用程序在网络上运行时可能无法达到理想的性能——例如,如果它们以小块的形式处理文件数据,那么闲聊会降低您的应用程序的速度。
【解决方案2】:

【讨论】:

  • 感谢您的回答。我在 IIS 中创建虚拟目录并通过 UNC 路径指向另一台服务器没有问题,当我尝试使用 wscript.shell 对象并将 unc 路径作为命令行参数之一传递时,问题就出现了。我相当确定这是 wscript.shell 对象或 ffmpeg 可执行文件无法访问 UNC 路径的权限问题。
  • @Ryan,必须是您的 ASP 所使用的帐户(通常是网络服务)非常有限(有充分的理由 )。我发现的大多数答案都指向使用模拟。也可以看看west-wind.com/weblog/posts/2153.aspx :)(抱歉,链接太多了..
【解决方案3】:

如果您发布了您遇到的特定错误,将会很有帮助。此请求使用什么类型的身份验证?如果您使用匿名,那么您需要使用域匿名用户,或者使用在目标服务器上具有相同用户名和密码的本地帐户。

【讨论】:

  • 问题是我没有收到错误, wscript.shell 命令只是无法执行。我试过写出 wffm.stdout.readall() 但没有任何东西打印到页面上,所以我不知道错误是什么。如果您对如何从 wscript.shell 获取错误文本有其他建议,请分享。 asp 脚本设置为在匿名访问下作为域用户运行。网站设置为在 IIS 中运行的 AppPool 被分配了网络服务帐户。
  • 进程监视器...您可以尝试运行进程监视器 (technet.microsoft.com/en-us/sysinternals/bb896645.aspx)。我有时在显示所有网络文件访问的进程监视器时遇到问题,但在某些情况下它会显示错误。尝试运行进程监视器并查找文件的失败条目。这应该告诉您正在访问该文件的用户,以及正在请求的访问权限。另一件事是尝试以匿名用户身份登录,看看您是否可以访问该文件。
  • 感谢您链接到的便捷工具。使用它,我看到 ffmpeg.exe 进程正试图作为 NT AUTHORITY\NETWORK SERVICE 运行,它必须无权将文件写入远程服务器。我该如何补救?我认为在 IIS 中设置页面以将匿名访问作为域帐户运行会导致页面上的所有内容都作为该域帐户运行?我设置页面的域帐户确实具有对远程服务器的读/写访问权限。我在 Proc Mon 中遇到的错误是对远程服务器路径的创建文件调用时访问被拒绝。
  • 这里有几个选项: 1) 更新 Web 服务进程,使其作为有权访问所需共享的域用户运行,而不是网络服务。 2) 您可以使用“net use” api,例如 WNetAddConnection() (msdn.microsoft.com/en-us/library/aa385413%28VS.85%29.aspx),将连接添加到远程共享作为不同的用户。这是解决此问题的一种更复杂的方法,但确实提供了使用本地和/或域用户帐户进行访问的最多选项。虽然它需要一些编码,但我之前已经使用过几次这种方法并且完全成功。