2

私は403を取得しているようです:

HTTP /1.1403サーバーがリクエストの認証に失敗しました。Authorizationヘッダーの値が署名を含めて正しく形成されていることを確認してください。

HttpWebRequest.DefaultCachingPolicyこれは、app.configで次のように setを使用すると発生します。

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

これを行っているのは、ファイルシステムであるかのように提供したblobストレージへのAPIを呼び出す、制御できないレガシーコードがあるためです(ファイルごとに最大58の同一の呼び出し)。明らかにこれは理想的ではありません。デフォルトのHTTPスタイルのキャッシュを使用することは、アプリケーションが変更されたときにのみファイルをダウンロードするようになるため、私が望む動作です。

この問題は、他のすべてのリクエストで発生しているようです(たとえば、リクエストがキャッシュされ、サーバーがサーバーのコンテンツが変更されているかどうかを確認しているときに発生しているようです)。

失敗したリクエストと成功したリクエストの唯一の違いは、次のものが含まれていることです。

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

1.7.1のgithubで.netAPI(私が使用している)のコードを確認しましたが、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();
        }
    }
}
4

2 に答える 2

0

BlobRequest.SignRequest(request, creds);ドキュメントをざっと見てみると、とIf-None-MatchIf-Modified-Since両方が、呼び出しが追加する Authentication ヘッダーの計算の一部として使用されていることがわかります。これらのヘッダーは、Authentication ヘッダーが WINInet によって計算された後に追加されるためです (推定)。いずれにせよ、最終結果は、Authentication ヘッダーによって提供されるチェックサムが無効になることです。したがって、403 Forbidden.

回避策:

  • アイテムを手動でローカルにキャッシュする
  • 呼び出し元のコードを修正します (おそらく長期的には最良の解決策です)
  • 残りのインターフェイスは非常に慎重に使用してください (実験では、これは同じ理由で危険であることが示されています。状況によっては、「Shared Key Lite」を使用するとこれを回避できます)。
  • 通常の WebRequest を使用してファイルを取得します (これは、共有キーまたはその他の方法でファイルをインターネットに公開する必要があることを意味します)

Azure Blob Storage が壊れているとは言いませんが、HTTP セマンティクスに正しく準拠できないため、真の RESTful ではないと言えます。

于 2012-11-15T20:23:18.487 に答える
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. 上記の例では、コンテナー ACL に関連付けられていない単純なポリシーを計算しているため、それを取り消す唯一の方法はストレージ キーをローテーションすることです。可能な限り、SAS 署名をコンテナー ポリシーに関連付けてください。この場合、SAS URI が漏洩/悪用された場合は、関連するコンテナーのポリシーを削除するだけで取り消すことができます。これを行う方法の詳細については、http: //msdn.microsoft.com/en-us/library/windowsazure/jj721951.aspxを参照してください。
  3. すべての SAS トラフィックは、特定のアカウントの SLA と請求にカウントされます。そのため、SAS URI は信頼できるクライアントとのみ共有されます。

ご不明な点がございましたら、お気軽にお問い合わせください。

/ジョー

于 2013-04-09T19:08:10.957 に答える