网络客户端下载数据安全漏洞?

问题描述

看看这段代码

public static void Main()
{
    try
    {
        WebClient client = new WebClient();
        byte[] data = client.DownloadData("http://website../../../page/1/2021-02/28/01/2021022801_brief.jpg");
        Console.WriteLine("data: " + data.Length);
    }
    catch(Exception exc)
    {
        Console.WriteLine(exc);
    }
}

在 .NET fiddle 上运行它(例如),你会得到这个异常:

System.Net.WebException: Could not find a part of the path 'C:\Resources\directory\2849ebba6307418392168ca985d98463.DotNetfiddle.Web.LocalResources\SandBox\67be885b-8fe4-40d0-b80e-cc2cfcbebfbe\page\1\2021-02\28\01\2021022801_brief.jpg'. ---> System.Net.WebException: Could not find a part of the path 'C:\Resources\directory\2849ebba6307418392168ca985d98463.DotNetfiddle.Web.LocalResources\SandBox\67be885b-8fe4-40d0-b80e-cc2cfcbebfbe\page\1\2021-02\28\01\2021022801_brief.jpg'. ---> System.IO.DirectoryNotFoundException: Could not find a part of the path 'C:\Resources\directory\2849ebba6307418392168ca985d98463.DotNetfiddle.Web.LocalResources\SandBox\67be885b-8fe4-40d0-b80e-cc2cfcbebfbe\page\1\2021-02\28\01\2021022801_brief.jpg'.
   at System.IO.__Error.WinIOError(Int32 errorCode,String maybeFullPath)
   at System.IO.FileStream.Init(String path,FileMode mode,FileAccess access,Int32 rights,Boolean useRights,FileShare share,Int32 bufferSize,FileOptions options,Security_ATTRIBUTES secAttrs,String msgPath,Boolean bFromProxy,Boolean useLongPath,Boolean checkHost)
   at System.IO.FileStream..ctor(String path,Boolean bFromProxy)
   at System.Net.FileWebStream..ctor(FileWebRequest request,String path,FileShare sharing,Int32 length,Boolean async)
   at System.Net.FileWebResponse..ctor(FileWebRequest request,Uri uri,Boolean asyncHint)
   --- End of inner exception stack trace ---
   at System.Net.FileWebResponse..ctor(FileWebRequest request,Boolean asyncHint)
   at System.Net.FileWebRequest.GetResponseCallback(Object state)
   --- End of inner exception stack trace ---
   at System.Net.WebClient.DownloadDataInternal(Uri address,WebRequest& request)
   at System.Net.WebClient.DownloadData(Uri address)
   at System.Net.WebClient.DownloadData(String address)
   at Program.Main() in d:\Windows\Temp\vbu5djxg.0.cs:line 13

你看到本地服务器路径了吗?!这怎么可能? URI 以 http 开头,为什么 .NET 尝试在本地查找文件

另外,如果 URL 是用户输入的,他们可以访问服务器文件夹信息......这不是一个安全漏洞吗?

解决方法

http://website../../../page/1/2021-02/28/01/2021022801_brief.jpg 不是有效的 URI。接受字符串的 DownloadData 的重载最终会调用 helper,该 WinHttpSendRequest failed with error code 87 具有将字符串转换为 URI 的这段代码:

    if (!Uri.TryCreate(path,UriKind.Absolute,out uri))
        return new Uri(Path.GetFullPath(path));

Uri.TryCreate 的调用将失败,因为 website.. 的 FQDN 无效。由于失败,它回退到 Path.GetFullPath

从那里开始,您将沿着向后兼容性工作和假设的深层隧道前进,这些假设将您的字符串视为 / 分隔的字符串和有效路径,并将其附加到当前工作目录。然后它冒泡为 file:// URI,当无法打开本地文件时,它会失败并显示您所看到的错误。

如果您在接受用户输入的 URI 的情况下,我建议您自己使用 Uri.TryCreateUriKind.Absolute 来构建 URI,并验证类型是一种您支持的类型(通常只是 HTTP 和 HTTPS)。您应该将任何其他内容视为错误并绕过某些辅助层。