衝突

2012-11-13 57 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。

我希望這可以幫助,讓我知道,如果你有其他疑問,

/喬