我正在尝试访问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¶ms=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;
}
}
}
答案 0 :(得分:1)
看来,这确实是Microsoft的RFC实现的bug:
System.Net类在“ Uri”中不包含查询字符串 摘要认证标头的属性。这是违反 RFC,并且某些Web服务器实现拒绝这些请求。
该帖子详细介绍了从this answer采取的变通方法。