使用错误的Uri的HttpClientHandler RFC 7616摘要身份验证标头

时间:2018-09-07 13:25:34

标签: c# http httpclient flurl

我正在尝试访问Lighttpd服务器上的资源,该服务器强制完整请求URI与授权请求标头中的URI匹配。这是在RFC 7616

中指定的
  

认证服务器必须确保指定的资源   通过“ uri”参数与在   请求行;如果不是,则服务器应返回400 Bad   请求错误。 (由于这可能是攻击的征兆,因此服务器
  实现者可能希望考虑记录此类错误。)目的
  从该字段中的请求URL复制信息的目的是
  处理中间代理可能更改
的可能性   客户的请求行。这发生了变化(但可能是语义上的
  等价)请求将不会产生与该摘要相同的摘要
  由客户计算得出。

我正在使用Flurl library(v1.4),它只是HttpClient的包装。但是,HttpClientHandler来自.Net。

为什么它使用基本URI而不使用完整URI?是虫子吗?如何使用完整的URI?

我想到了将另一个 HttpMessageHandler 添加到管道中,并使用完整的URI修改 Authentication 标头,但是 HttpClientHandler 不允许您设置 InnerHandler

完整的 Uri应该http://base/resource.cgi?my=1&params=2

但这是请求标头中显示的内容:

  

授权:摘要   username =“ user”,realm =“ serve”,nonce =“ 5b911545:eaf4352d2113e5e4b1ca253bd70fd90a”,    uri =“ / base / resource.cgi” ,cnonce =“ bf7cf40f1289bc10bd07e8bf4784159c”,nc = 00000001,qop =“ auth”,response =“ cf3c731ec93f7e5928f19f880f8325ab”

导致400错误的请求响应。

我的Flurl代码:

HttpClient工厂

    /// <summary>
    /// Custom factory to generate HttpClient and handler to use digest authentication and a continuous stream
    /// </summary>
    private class DigestHttpFactory : Flurl.Http.Configuration.DefaultHttpClientFactory
    {
        private CredentialCache CredCache { get; set; }

        public DigestHttpFactory(string url, string username, string password) : base()
        {
            Url = url;

            CredCache = new CredentialCache
            {
                { new Uri(Url), "Digest", new NetworkCredential(username, password) }
            };
        }

        private string Url { get; set; }

        public override HttpClient CreateHttpClient(HttpMessageHandler handler)
        {
            var client = base.CreateHttpClient(handler);
            client.Timeout = TimeSpan.FromMilliseconds(Timeout.Infinite); // To keep stream open indefinietly
            return client;
        }

        public override HttpMessageHandler CreateMessageHandler()
        {
            var handler = new HttpClientHandler
            {
                Credentials = CredCache.GetCredential(new Uri(Url), "Digest")
            };


            return handler;
        }
    }

请求代码

public class MyConnection
{
    public string BaseUrl => "http://base/resource.cgi";

    public async Task ConnectAsync(CancellationToken cancellationToken = default(CancellationToken))
    {
        ConnectionCancellation = new CancellationTokenSource();

        var url = BaseUrl
            .SetQueryParam("my", 1)
            .SetQueryParam("params", 2)

        FlurlHttp.ConfigureClient(url, client =>
        {
            client.Configure(settings =>
            {
                settings.HttpClientFactory = new DigestHttpFactory(url, Username, Password);
            });
        });

        try
        {
            using (var getResponse = url.GetAsync(cancellationToken, HttpCompletionOption.ResponseHeadersRead))
            {
                var responseMessage = await getResponse;

                using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(ConnectionCancellation.Token, cancellationToken))
                using (var stream = await responseMessage.Content.ReadAsStreamAsync())
                    await Process(stream, linkedCts.Token);
            }
        }
        catch (OperationCanceledException ex)
        {
            throw ex;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }
}

1 个答案:

答案 0 :(得分:1)

看来,这确实是Microsoft的RFC实现的bug

  

System.Net类在“ Uri”中不包含查询字符串   摘要认证标头的属性。这是违反   RFC,并且某些Web服务器实现拒绝这些请求。

该帖子详细介绍了从this answer采取的变通方法。