如何在 Azure 中允许 URL 编码的路径段

Posted

技术标签:

【中文标题】如何在 Azure 中允许 URL 编码的路径段【英文标题】:How do I allow URL encoded path segments in Azure 【发布时间】:2016-05-12 06:32:39 【问题描述】:

我有一个在 Azure 中运行的 ASP.NET 6 MVC 应用程序。我有一个控制器,其动作类似于

[HttpDelete]
[Route("image_url")]
public async Task<IActionResult> RemoveImageUrl([FromRoute(Name = "image_url")] String imageUrlString)

然后我就这样称呼它

api/https%3A%2F%2Frepocreator.zoltu.io%2Fimages%2FZoltu-Logo-Full-Size.png"

当使用 Kestrel 自托管时,此应用程序运行良好,但一旦我部署到 Azure,我就会收到 500 个错误。我已经尽可能多地进行了调试,经过大量的谷歌搜索和戳,似乎 IIS 正在尝试对请求进行有用的 URL 解码,然后再将其转发到 ASP.NET 进行处理。当然,问题是即使我可以说服 IIS 接受请求

<system.webServer>
    <security>
        <requestFiltering allowDoubleEscaping="true" />
    </security>
</system.webServer>
<system.web>
    <httpRuntime requestValidationMode="2.0" requestPathInvalidCharacters="" relaxedUrlToFileSystemMapping="true"/>
    <pages validateRequest="false" />
</system.web>

它仍然对 URL 进行解码,并将解码后的 URL 传递给 ASP.NET,它没有找到匹配的路由。

我能做些什么来告诉 IIS 停止在这里提供帮助,而只是传递它获得的任何 URL,而不进行任何形式的预验证或重写?注意:这是一个 Azure Web App,所以我无法直接访问 IIS 设置。

【问题讨论】:

Micah,我遇到了类似的问题...你有没有想出一个令人满意的解决方案? 我最终找到的解决方案是停止使用 IIS 托管。我不记得我是否解决了这个 specific 解决方案,但总的来说 IIS 最终比它的价值更痛苦。我现在用 Kestrel 在 docker 中运行我所有的东西,我的生活变得简单多了。 哈。好的,谢谢。 2019 年了,这仍然是个问题 smh 我最终只是对一些 url 参数进行了 b64 编码 【参考方案1】:

您可以更新您的路线定义,使其与解码的图像 url 参数相匹配。

根据the documentation,在定义路由模板时:

您可以使用 * 字符作为路由值名称的前缀来绑定 到 URI 的其余部分。例如, blog/*slug 将匹配任何 URI 以 /blog/ 开头并在其后有任何值(这将 分配给 slug 路线值)。

所以你可以创建一个匹配路由[Route("*image_url")]的动作:

[Route("*image_url")]
public IActionResult RemoveImageUrl([FromRoute(Name = "image_url")]String imageUrlString)

    return Json(new  ReceivedImage = imageUrlString );

我看到的唯一问题是协议部分被解码为http:/,带有一个/。你有几个选择:

您可以在控制器中手动修复它。更好的是,您可以创建一个模型绑定器和一个参数约定来自动执行此操作:

[HttpDelete]
[Route("*image_url")]
public IActionResult RemoveImageUrl([FullUrlFromEncodedRouteParam(Name = "image_url")] String imageUrlString)            

    return Json(new  ReceivedImage = imageUrlString );


public class FullUrlFromUrlEncodedPathSegmentModelBinder : IModelBinder

    //Matches a url that starts with protocol string and is followed by exactly ":/" instead of "://"
    private static Regex incorrectProtocolRegex = new Regex(@"^([a-z][\w-]+:)\/1(?!\/)");

    //A url path included as a url encoded path segment like http://localhost:39216/image2/https%3A%2F%2Frepocreator.zoltu.io%2Fimages%2FZoltu-Logo-Web.png
    //will be decoded by IIS as https:/repocreator.zoltu.io/images/Zoltu-Logo-Web.png, note the single '/' after the protocol
    //This model binder will fix it replacing "http:/" with "http://"
    public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext)
    
        if (bindingContext.ValueProvider.GetValue(bindingContext.ModelName) == null)
            return Task.FromResult(ModelBindingResult.NoResult);                            

        var val = bindingContext.ValueProvider.GetValue(bindingContext.ModelName).FirstValue as string;
        var fixedVal = incorrectProtocolRegex.Replace(val, @"$1//");                                                
        return Task.FromResult(ModelBindingResult.Success(bindingContext.ModelName, fixedVal));                        
    


public class FullUrlFromEncodedRouteParamAttribute : Attribute, IParameterModelConvention

    public string Name  get; set; 

    public void Apply(ParameterModel parameter)
    
        parameter.BindingInfo = parameter.BindingInfo ?? new BindingInfo();
        parameter.BindingInfo.BinderModelName = Name;
        parameter.BindingInfo.BindingSource = BindingSource.Path;
        parameter.BindingInfo.BinderType = typeof(FullUrlFromUrlEncodedPathSegmentModelBinder);         
    

更好的方法可能是更新您的 api,这样您甚至不使用图像密钥中的协议部分。这将允许您在需要呈现完整图像 url 时添加正确的协议,具体取决于它是否需要 http 或 https(甚至可以从 url 中省略主机)。您甚至不需要担心在客户端对图像路径进行 url 编码,您可以像 http://localhost:39216/api/repocreator.zoltu.io/images/Zoltu-Logo-Full-Size.png 一样调用它。

恕我直言,我更喜欢第二种方法。如果你真的需要在路由中编码的完整 url,那么至少你有办法在控制器之外以干净的方式实现它。

注意:如果要保留图片url中的协议部分,看起来静态文件中间件不喜欢它们,所以必须在Startup.configure的MVC之后添加,否则它会抛出错误。

【讨论】:

虽然您的建议可以让我解决当前的问题(前端和后端都进行了更改),但它并没有解决根本问题,即如何在 Azure 中制作 IIS NOT URL 解码请求,然后将其传递给我的框架。 IIS 的行为违反了 URL 规范,我真的想要一种方法来使用 URL 编码的设计方式,并且以一种可跨 Web 服务器移植且灵活的方式(API 用户不必知道IIS)。 我同意它不会改变 Azure 处理 url 的方式,但用户不需要了解 Azure 的细节不是吗? http://localhost:39216/api/repocreator.zoltu.io%2Fimages%2FZoltu-Logo-Full-Size.pnghttp://localhost:39216/api/repocreator.zoltu.io/images/Zoltu-Logo-Full-Size.png 都可以正常工作。 除非我误解了您的建议,否则如果我的 API 用户使用 .../api/https%3A%2F%2Frepocreator.zoltu.io%2Fimages%2FZoltu-Logo-Web.png 调用它,事情将会崩溃,因为 IIS 会误解 URL 编码 //。这意味着行为合理的用户将失败,因为后端恰好在 IIS 上运行(并且未正确处理 URL 编码)。如果后端在 Kestrel 上运行,则请求将是有效的。 是的,如果你真的想在 api 中包含协议,那么你就会遇到这个问题(你仍然可以在控制器中修复)。但是,如果用户不需要对完整路径进行 url 编码,甚至不需要担心协议或主机,恕我直言是一件好事(如dropbox api v1 或api v2)。如果您更改主机或使用 https,这些图像会怎样?

以上是关于如何在 Azure 中允许 URL 编码的路径段的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Elastic Beanstalk 负载均衡器环境中允许编码斜杠

如何在 WebView Flutter 中允许 mailto 和 tel URL 方案?

如何在[PHP]中允许跨域[重复]

在 CodeIgniter 中允许 URL 中的任何字符

在 Spring 安全性中允许除一个之外的所有 URL

如何解决 cors 在 vue js 和 laravel 应用程序中允许访问控制