Azure Service Bus 中的身份驗證方式 Shared Access Signature


Azure Service Bus 中的身份驗證方式 Shared Access Signature

警告

您當前查看的頁面是未經授權的轉載!
如果當前版本排版錯誤,請前往查看最新版本:http://www.cnblogs.com/qin-nz/p/azure-service-bus-shared-access-signature-token.html

提示

更新時間:2016年01月01日。

今天踩了一個坑……

在 Azure 的 Service Bus (服務總線) 中,每個請求是需要保護一個驗證信息的。 這個驗證信息可以是SAS,也可以是ACS(已經不建議使用)。

注解

如果是可以安全保存Key的服務器想要訪問 Service Bus,並且不是使用.NET Core,是不需要知道有SAS Token 這種東西存在的。

小技巧

Azure Storage 對於非public的文件方法也是使用這個的思想,但用於簽名的具體參數不同。

Shared Access Signature 機制

Shared Access Signature ,從名字上不難看出,這是一個通過簽名來共享訪問權限的機制。 在 Service Bus 中,我們有一個名為 RootManageSharedAccessKey 的Key, 這個 Key 擁有這個 Service Bus 的完整訪問權限。 我們可以為每個隊列/主題/事件中心 創建獨立的Key,甚至可以為他們分配不同的權限。

注解

在管理門戶中看到的 Key 一般有兩個, PrimaryKeySecondaryKey ,任意一個都可用。 兩個的目的是方便定期更換密鑰,建議使用 PrimaryKey

由於 Service Bus 的發送方可能是終端設備,比如IoT設備等,就這樣把Key下發下去很不安全,因此可以 Shared Access Signature 機制。

當我們需要訪問某個資源,如 https://qinnz.servicebus.windows.net/myeventhub/message 時, 我們用剛剛的key對這個資源和可訪問的有效期進行簽名,並把簽名+資源+有效期三項內容發給服務器,服務器即可進行簽名驗證。

Shared Access Signature 生成過程

這里,我們就用 RootManageSharedAccessKey 密鑰進行簽名。

  • 對資源Uri進行encode,資源Uri可以是請求的資源或者它的父資源。
  • 得到過期時間的Unix時間戳(Azure Storage 使用的是人可識別的日期格式)
  • 將Key使用 UTF-8 編碼轉換為字節數組,作為簽名密鑰
  • 對資源uri和時間戳進行簽名(使用 HMAC-SHA256 算法)
  • 生成簽名字符串
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
    public class SasToken
    {
        public static string Generator(string uri, DateTimeOffset expiryTime, string keyName, string keyValue)
        {
            string uriEncoded = Uri.EscapeDataString(uri.ToString());
            long expiry = expiryTime.ToUnixTimeSeconds();  //Only available on .Net 4.6
            byte[] key = Encoding.UTF8.GetBytes(keyValue);
            var hmac = new HMACSHA256(key);
            string stringToSign = uriEncoded + "\n" + expiry.ToString();
            string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
            Debug.WriteLine(stringToSign);
            return $"SharedAccessSignature sr={uriEncoded}&sig={Uri.EscapeDataString(signature)}&se={expiry}&skn={keyName}";
        }
    }

嗯,上面就是我自己實現的……坑就在於第7行……

在微軟官方文檔中,他們也以為是 base64 編碼的,我剛剛在Github上提交了這個 issue

事實上,微軟官方是有C#類庫來做這件事的(下面第15行); 我自己實現僅為了能在別的平台上能用。 下面說說官方給出的實現代碼和我的代碼做比較,注意替換自己的key和keyName:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;
using Microsoft.ServiceBus;

namespace SharedAccessSignatureTokenGenerator
{
    class Program
    {
        private static string resource = "<your-resource>";
        private static string key = "<your-key-for-RootManageSharedAccessKey>";
        private static string keyName = "RootManageSharedAccessKey";

        static void Main(string[] args)
        {
            // Get Token using  Microsoft.ServiceBus.SharedAccessSignatureTokenProvider.GetSharedAccessSignature
            var token = SharedAccessSignatureTokenProvider.GetSharedAccessSignature(keyName, key, resource, new TimeSpan(24, 0, 0));

            //Get Token using my SasToken.Generator
            long se = long.Parse(token.Substring(token.IndexOf("se=") + 3, 10));
            var mytoken = SasToken.Generator(resource, new DateTimeOffset(2050, 1, 1, 0, 0, 0, new TimeSpan()), keyName, key);

            Console.WriteLine(mytoken);
            Console.WriteLine(token);
        }
    }
}

注解

由於我使用的 Uri.EscapeDataString 返回的是大寫字母,造成簽名值不一樣;不過因為sr同樣不一樣,並沒有什么影響。

可以使用 uriEncoded=uriEncoded.ToLower(); 使得兩種方法簽名一致。

訪問測試

現在,就可以向 Service Bus 發送消息了。

注解

Event Hub 的API可以參考 這里

例如我們可以向 sb://qinnz.servicebus.windows.net/mail/messages 發送消息, 可以指定 srsb://qinnz.servicebus.windows.net/mail/messagessb://qinnz.servicebus.windows.net (如果key的權限足夠,那么此時的SAS具有整個servicebus的訪問權限) 我們需要設定SAS的過期時間,已經你使用的密鑰的名字,使Azure可以在服務器端驗證簽名。

最終,我們生成下面的字符串作為HTTP請求的Authorization請求頭。

SharedAccessSignature sr=sb%3A%2F%2Fqinnz.servicebus.windows.net%2Fmail%2Fmessages
&sig=Augn3gnz4PEz%2Faaaaaaaaaaaaaaaaaaaacr%2B4vd2tWE%3D
&se=2000000000&skn=RootManageSharedAccessKey

下面我就用 Fiddler 模擬發送POST請求,內容如下(處於安全原因,我替換了簽名值):

1
2
3
4
5
6
7
POST https://qinnz.servicebus.windows.net/mail/messages
Authorization: SharedAccessSignature sr=sb%3A%2F%2Fqinnz.servicebus.windows.net%2Fmail%2Fmessages&sig=Augn3gnz4PEz%2Faaaaaaaaaaaaaaaaaaaacr%2B4vd2tWE%3D&se=2000000000&skn=RootManageSharedAccessKey
Content-Type: application/atom+xml;type=entry;charset=utf-8
Host: qin-nz.servicebus.windows.net
Content-Length: 5

hello!

聲明 知識共享許可協議

Azure Service Bus 中的身份驗證方式 Shared Access Signature勤奮的小孩 創作,采用 知識共享 署名-相同方式共享 4.0 國際 許可協議進行許可。
本許可協議授權之外的使用權限可以從 http://space.cnblogs.com/msg/send/qin-nz 處獲得。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM