冲突

2012-11-13 54 views
2

我似乎得到403:冲突

HTTP/1.1 403服务器无法验证请求。确保授权标头的值正确形成,包括签名。

发生这种情况时,我设置使用的HttpWebRequest.DefaultCachingPolicy在App.config如下:

<system.net> 
<requestCaching defaultPolicyLevel="Default" isPrivateCache="false"> 
    <defaultHttpCachePolicy policyLevel="Default"/> 
</requestCaching> 
</system.net> 

我这样做是因为我有旧的代码,我不控制被调用API将我提供的存储作为一个文件系统提供(每个文件最多58个相同的调用)。显然这并不理想。使用默认的HTTP风格缓存是我想要的行为,因为它会导致我的应用程序在修改文件时只下载文件。

这个问题似乎发生所有其他请求(例如,它出现时,该请求被缓存服务器检查,以查看是否在服务器内容已更改,将发生)。

失败的请求和成功的请求之间唯一的区别似乎是列入:

If-None-Match: "<a blob etag>" 
If-Modified-Since: <a date> 

我看过了.NET API的代码(我使用的)在github 1.7.1上,并假设它没有从SDK 1.6(我目前使用的)中更改,它应该可以正常工作。

任何帮助是非常赞赏

更新: 我已经写了一些摄制的代码,以帮助:

用途:.NET 4.0,Windows Azure的SDK 1.6

using System; 
using System.Net; 
using System.Net.Cache; 
using Microsoft.WindowsAzure; 
using Microsoft.WindowsAzure.StorageClient; 

namespace AzureStorageProb 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      const string accountKey = "<azure storage account key>"; 
      const string account = "<azure storage account name>"; 
      const string testBlob = "<blob path to test file>"; 
      var cloudStorageAccount = 
       new CloudStorageAccount(
        new StorageCredentialsAccountAndKey(account, accountKey), 
        useHttps: true); 
      var cloudBlobClient = cloudStorageAccount.CreateCloudBlobClient(); 
      HttpWebRequest.DefaultCachePolicy = 
       new HttpRequestCachePolicy(HttpRequestCacheLevel.Default); 

      try 
      { 
       var blob = cloudBlobClient.GetBlobReference(testBlob); 
       blob.FetchAttributes(); 
       blob.DownloadByteArray(); 
       Console.WriteLine("First attempt worked!"); 
      } 
      catch (StorageClientException ex) 
      { 
       Console.WriteLine(ex); 
      } 

      try 
      { 
       var blob = cloudBlobClient.GetBlobReference(testBlob); 
       blob.FetchAttributes(); 
       blob.DownloadByteArray(); 
       Console.WriteLine("Second attempt worked!"); 
      } 
      catch (StorageClientException ex) 
      { 
       Console.WriteLine(ex); 
      } 
      Console.ReadKey(); 
     } 
    } 
} 

回答

0

因此,原来出错的原因是BlobRequest.SignRequest(request, creds);快速浏览文档指出If-None-MatchIf-Modified-Since都被用作计算调用添加的Authentication标头的一部分。因为这些标题是在WINInet(推定)计算出的验证标头之后添加的。无论哪种方式,最终的结果是由验证标头提供的校验和现在是无效的。从而导致403 Forbidden

变通:

  • 手动缓存在本地项目
  • 修复调用代码(可能是最好的长期解决方案)
  • 使用REST接口非常谨慎(实验显示出这是危险的由于同样的原因,使用“共享密钥精简版”解决此获得在某些情况下)
  • 使用常规的WebRequest获取文件夹(这意味着你必须将它们暴露在Internet上,或者通过共享密钥或其他方式)

我不会说Azure Blob存储已损坏......但我会说它并不是真正的RESTful,因为它无法正确遵守HTTP语义。

0

这是失败的原因实施是计算的签名包括请求日期以及条件标题(如果匹配,如果没有匹配,如果修改后等),以防止重播或人在中间的攻击。因此,当发送缓存的请求时,认证失败。 目前似乎没有办法挂钩默认HTTP缓存并更改标头以更新此签名,因为SharedKey和SharedKeyLite身份验证方案不适用于此方案。 但是,您可以利用SharedAccessSignatures(http://msdn.microsoft.com/en-us/library/windowsazure/ee395415.aspx)对某个给定的URI进行一段时间的预先验证。这将不再需要每个请求唯一的签名。

SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy() 
{ 
    Permissions = SharedAccessBlobPermissions.Read, 

    // Add delta to account for clock skew 
    SharedAccessStartTime = DateTime.Now.AddMinutes(-5), 
    SharedAccessExpiryTime = DateTime.Now.AddMinutes(15) 
}; 

HttpWebRequest.DefaultCachePolicy = new HttpRequestCachePolicy(HttpCacheAgeControl.MaxAge, TimeSpan.FromSeconds(10)); 
CloudBlockBlob sasdBlob = new CloudBlockBlob(new Uri(rootBlob.Uri.ToString() + rootBlob.GetSharedAccessSignature(policy))); 

OperationContext cacheCtx = new OperationContext(); 
cacheCtx.ResponseReceived += (o, a) => Console.WriteLine("{0} : {1}", a.RequestInformation.HttpStatusCode, a.Response.IsFromCache); 

for (int m = 0; m < 100; m++) 
{ 
    sasdBlob.DownloadToStream(Stream.Null, null, null, cacheCtx); 
    Thread.Sleep(1000); 

    if (m == 10) 
    { 
      // invalidate data updating properties 
      rootBlob.Metadata.Add("hello", "cache"); 
      rootBlob.SetMetadata(); 
    } 
} 

这将输出:

200:假

200:真

200:真

200:真

200:真

200:真

200:真

200:真

200:真

200:真

200:真

200:错误

200:真

...

我们将寻找更好的方法来没有在未来这样的解决方法公开此功能。

阅读本篇!

无论何时您使用SharedAccessSignatures,您都必须在URI本身内部发布密钥。因此,应遵循一些安全最佳实践。

  1. 如果您在DC外部或通过可能受监视的链接运行,请使用HTTPS来防止恶意操作者滥用签名。
  2. 上面的示例计算了一个与Container ACL无关的简单策略,因此撤销它的唯一方法是旋转存储密钥。请尽可能将SAS签名与容器策略相关联。在这种情况下,如果SAS Uri被泄露/滥用,您可以通过简单地删除相关容器上的策略来撤消它。有关如何执行此操作的更多信息,请参阅:http://msdn.microsoft.com/en-us/library/windowsazure/jj721951.aspx
  3. 所有SAS流量均计入给定帐户SLA和帐单,因此仅与可信客户端共享SAS URI。

我希望这可以帮助,让我知道,如果你有其他疑问,

/乔