导出 (0) 打印
全部展开

Azure 存储服务身份验证

更新时间: 2014年5月

除非请求可以通过公共或签名访问方式访问的 Blob 或容器资源,否则对存储服务的每一个请求都必须经过身份验证。

Important重要提示
Microsoft Azure 存储服务支持 HTTP 和 HTTPS,不过强烈建议你使用 HTTPS。

从版本 2009-09-19(针对 Blob、队列和表服务)和版本 2014-02-14(针对文件服务)开始,Blob、队列、表和文件服务支持以下共享密钥身份验证方案:

  • 用于 Blob、队列和文件服务的共享密钥。使用共享密钥身份验证方案发出对 Blob、队列和文件服务的请求。版本 2009-09-19 的共享密钥身份验证方案支持附加签名字符串以提高安全性,你需要更新服务以使用此附加签名进行身份验证。

  • 用于表服务的共享密钥。使用共享密钥身份验证方案,通过 REST API 请求表服务。版本 2009-09-19 的表服务共享密钥身份验证使用与先前版本的表服务相同的签名字符串。

  • 共享密钥 Lite。使用共享密钥 Lite 身份验证方案发出对 Blob、队列、表和文件服务的请求。

    对于版本 2009-09-19 的 Blob 和队列服务,共享密钥 Lite 身份验证支持使用与之前版本的 Blob 和队列服务中共享密钥支持的相同签名字符串。因此,可以使用共享密钥 Lite 请求 Blob 和队列服务,而无需更新签名字符串。

经过身份验证的请求需要两个标头:Datex-ms-date 标头,以及 Authorization 标头。以下几节介绍如何构造这些标头。

note备注
容器和 blob 可通过设置其容器的权限来允许公共访问。有关详细信息,请参阅管理对 Azure 存储资源的访问。容器、blob、队列或表允许通过共享访问签名进行签名访问;共享访问签名通过不同的机制进行身份验证。有关详细信息,请参阅使用共享访问签名委托访问权限

所有接受身份验证的请求都必须包括请求的协调世界时 (UTC) 时间戳。可以在 x-ms-date 标头中或在标准 HTTP/HTTPS Date 标头中指定时间戳。如果在请求中同时指定这两个标头,则使用 x-ms-date 的值作为请求的创建时间。

存储服务确保到请求获得服务时,请求的存在时间不超过 15 分钟。这能防范某些安全攻击,包括重放攻击。如果此检查失败,服务器将返回响应码 403(已禁止)。

note备注
提供 x-ms-date 标头,因为一些 HTTP 客户端库和代理会自动设置 Date 标头,开发人员无法读取其值并将其包含在接受身份验证的请求之内。如果设置 x-ms-date,则对 Date 标头使用空值来构造签名。

接受身份验证的请求必须包括 Authorization 标头。如果不包括此标头,则请求将匿名发出,且只有对为实现公共访问而标记的容器或 blob,或者对为实现委托访问而获得共享访问签名的容器、blob、队列或表才能成功。

要对请求进行身份验证,必须用提出请求的帐户的密钥来签署请求,并将签名包含在请求中进行传递。

Authorization 标头的格式如下所示:

Authorization="[SharedKey|SharedKeyLite] <AccountName>:<Signature>"

其中 SharedKeySharedKeyLite 是授权方案的名称,AccountName 是请求资源的帐户的名称,Signature 是基于散列的消息身份验证代码 (HMAC),该代码基于请求构造,并使用 SHA256 算法计算,然后使用 Base64 编码方式进行编码。

note备注
如果驻留在不同帐户下的资源是允许公共访问的资源,则可以请求该资源。

以下几节介绍如何构造 Authorization 标头。

如何构造签名字符串取决于要进行身份验证的服务和版本以及使用的身份验证方案。构造签名字符串时,请注意以下几点:

  • 字符串的 VERB 部分是 HTTP 动词,如 GET 或 PUT,必须为大写形式。

  • 对于 Blob、队列和文件服务的共享密钥身份验证,包括在签名字符串中的每个标头都只能出现一次。如果有任何标头重复,则服务将返回状态码 400(错误请求)。

  • 所有标准 HTTP 标头的值都必须按照签名格式中所示顺序包括在字符串中,且不含头名称。如果这些标头未指定为请求的一部分,则可能为空;在这种情况下,只需要换行符。

  • 如果指定 x-ms-date 标头,则可以忽略 Date 标头,不管它是否在请求中指定,只需为签名字符串的 Date 部分指定空行。在这种情况下,请遵照构造规范化标头元素一节中的说明,添加 x-ms-date 标头。

    请注意,可以同时指定 x-ms-dateDate;在这种情况下,该服务将使用 x-ms-date 的值。

  • 如果未指定 x-ms-date 标头,请在签名字符串中指定 Date 标头,且不指定标头名称。

  • 签名字符串中必须包含显示的所有换行符 (\n)。

  • 有关构造组成签名字符串的 CanonicalizedHeadersCanonicalizedResource 字符串的详细信息,请参见本主题中后面对应的小节。

若要针对 2009-09-19 版本或更高版本的 Blob 或队列服务请求以及 2014-02-14 版本或更高版本的文件服务请求为共享密钥签名字符串进行编码,请采用以下格式:

StringToSign = VERB + "\n" +
               Content-Encoding + "\n"
               Content-Language + "\n"
               Content-Length + "\n"
               Content-MD5 + "\n" +
               Content-Type + "\n" +
               Date + "\n" +
               If-Modified-Since + "\n"
               If-Match + "\n"
               If-None-Match + "\n"
               If-Unmodified-Since + "\n"
               Range + "\n"
               CanonicalizedHeaders + 
               CanonicalizedResource;

下面的示例是获取 Blob 操作的签名字符串。请注意,对于没有标头值的情况,将仅指定换行符。

GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Sun, 11 Oct 2009 21:49:13 GMT\nx-ms-version:2009-09-19\n/myaccount/myaccount/mycontainer\ncomp:metadata\nrestype:container\ntimeout:20

逐行拆分将显示相同字符串的每一个部分:


GET\n /*HTTP Verb*/
\n    /*Content-Encoding*/
\n    /*Content-Language*/
\n    /*Content-Length*/
\n    /*Content-MD5*/
\n    /*Content-Type*/
\n    /*Date*/
\n    /*If-Modified-Since */
\n    /*If-Match*/
\n    /*If-None-Match*/
\n    /*If-Unmodified-Since*/
\n    /*Range*/
x-ms-date:Sun, 11 Oct 2009 21:49:13 GMT\nx-ms-version:2009-09-19\n    /*CanonicalizedHeaders*/
/myaccount/myaccount/mycontainer\ncomp:metadata\nrestype:container\ntimeout:20    /*CanonicalizedResource*/

接下来,对采用 UTF-8 编码的签名字符串使用 HMAC-SHA256 算法进行编码,构造 Authorization 标头,并将该标头添加到请求。下面的示例是用于相同操作的 Authorization 标头:

Authorization: SharedKey myaccount:ctzMq410TV3wS7upTBcunJTDLEJwMAZuFPfr0mrrA08=

请注意,为了对 2009-09-19 版本的 Blob 和队列服务使用共享密钥身份验证,必须更新代码以使用此附加签名字符串。

如果想尽量少做更改,将代码迁移到 2009-09-19 版本的 Blob 和队列服务,则可以修改现有 Authorization 标头以使用共享密钥 Lite 而不是共享密钥。共享密钥 Lite 要求的签名格式与 2009-09-19 之前版本的 Blob 和队列服务的共享密钥要求的格式相同。

如果服务使用 REST API 来请求表服务,则必须使用共享密钥身份验证对请求进行身份验证。表服务共享密钥的签名字符串的格式对所有版本都相同。

请注意,用于表服务请求的共享密钥签名字符串与用于 Blob 或队列服务请求的共享密钥签名字符串略有不同,区别在于它不包括字符串的 CanonicalizedHeaders 部分。此外,这种情况下,Date 标头不会为空,即使请求设置了 x-ms-date 标头也不例外。如果请求设置 x-ms-date,则也会使用该值作为 Date 标头值。

要对使用 REST API 的表服务请求的签名字符串进行编码,请使用以下格式:

StringToSign = VERB + "\n" + 
               Content-MD5 + "\n" + 
               Content-Type + "\n" +
               Date + "\n" +
               CanonicalizedResource;

note备注
从版本 2009-09-19 开始,表服务要求所有 REST 调用都包括 DataServiceVersionMaxDataServiceVersion 标头。有关更多信息,请参见设置 OData 数据服务版本标头

可以使用共享密钥 Lite 身份验证对 2009-09-19 版本的 Blob 和队列服务请求以及 2014-02-14 版本的文件服务请求进行身份验证。

共享密钥 Lite 的签名字符串与 2009-09-19 之前的 Blob 和队列服务版本的共享密钥身份验证所要求的签名字符串相同。因此,如果希望尽量少更改 2009-09-19 版本的 Blob 和队列服务实现代码迁移,可以将代码修改为使用共享密钥 Lite,而无需更改签名字符串本身。请注意,使用共享密钥 Lite 时,不会获得使用 2009-09-19 版本 API 的共享密钥时提供的增强安全功能。

要对用于 Blob 或队列服务请求的签名字符串进行编码,请使用以下格式:

StringToSign = VERB + "\n" +
               Content-MD5 + "\n" +
               Content-Type + "\n" +
               Date + "\n" +
               CanonicalizedHeaders + 
               CanonicalizedResource;

下面的示例是放置 Blob 操作的签名字符串。请注意,Content-MD5 标头行为空。显示在该字符串中的标头是指定新 Blob 的自定义元数据值的名称/值对。

PUT\n\ntext/plain; charset=UTF-8\n\nx-ms-date:Sun, 20 Sep 2009 20:36:40 GMT\nx-ms-meta-m1:v1\nx-ms-meta-m2:v2\n/testaccount1/mycontainer/hello.txt

接下来,对采用 UTF-8 编码的签名字符串使用 HMAC-SHA256 算法进行编码,构造 Authorization 标头,并将该标头添加到请求。下面的示例是用于相同操作的 Authorization 标头:

Authorization: SharedKeyLite myaccount:ctzMq410TV3wS7upTBcunJTDLEJwMAZuFPfr0mrrA08=

可以使用共享密钥 Lite 身份验证对任何版本的表服务请求进行身份验证。

要对使用共享密钥 Lite 的表服务请求的签名字符串进行编码,请使用以下格式:

StringToSign = Date + "\n" 
               CanonicalizedResource

下面的示例是创建表 操作的签名字符串。

Sun, 11 Oct 2009 19:52:39 GMT\n/testaccount1/Tables

接下来,使用 HMAC-SHA256 算法对此字符串进行编码,构造 Authorization 标头,然后将该标头添加到请求。下面的示例是用于相同操作的 Authorization 标头:

Authorization: SharedKeyLite testaccount1:uay+rilMVayH/SVI8X+a3fL8k/NxCnIePdyZSkqvydM=

要构造签名字符串的 CanonicalizedHeaders 部分,请执行以下步骤:

  1. 检索以 x-ms- 开头的所有资源标头,包括 x-ms-date 标头。

  2. 将每个 HTTP 标头名称转换为小写形式。

  3. 以升序基于标头名称按字母顺序对标头进行排序。请注意,每个标头在字符串中只出现一次。

  4. 用一个空格替换所有换行空格,从而取消字符串的断行。

  5. 修剪标头中冒号旁边的空格。

  6. 最后,在产生的列表中的每一个规范化标头之后追加一个换行符。将此列表中的所有标头连接起来成为一个字符串,构造 CanonicalizedHeaders 字符串。

签名字符串的 CanonicalizedResource 部分表示要请求的存储服务资源。源自资源 URI 的CanonicalizedResource 字符串的任何部分都应该安全按照其在 URI 中的形式进行编码。

对于 CanonicalizedResource 字符串,支持以下两种格式:

  • 一种格式支持对 2009-09-19 版本的 Blob 和队列服务以及 2014-02-14 版本的文件服务进行共享密钥身份验证。

  • 一种格式支持用于所有版本表服务的共享密钥和共享密钥 Lite,以及用于 2009-09-19 版本 Blob 和队列服务的共享密钥 Lite。此格式与用于先前版本的存储服务的格式相同。

有关为要访问的资源构造 URI 的帮助,请参见以下主题之一:

note备注
如果要对存储模拟器进行身份验证,则帐户名将在 CanonicalizedResource 字符串中出现两次。这样才是正确的。如果要对 Azure 存储服务进行身份验证,则帐户名在 CanonicalizedResource 字符串中将只出现一次。

2009-09-19 共享密钥格式

此格式支持对 2009-09-19 版本的 Blob 和队列服务以及 2014-02-14 版本的文件服务进行共享密钥身份验证。按照如下格式构造 CanonicalizedResource 字符串:

  1. 以空字符串 ("") 开头,随后追加一个正斜杠 (/),再接拥有待访问资源的帐户的名称。

  2. 不带任何查询参数,附加该资源的编码 URI 路径。

  3. 检索资源 URI 的所有查询参数,包括 comp 参数(如果有)。

  4. 将所有参数名称转换为小写形式。

  5. 以升序基于参数名称按字母顺序对查询参数进行排序。

  6. 对每个查询参数名称和值进行 URL 解码。

  7. 按以下格式在该字符串之后附加每个查询参数名称和值,并确保在名称与值之间使用冒号 (:):

    parameter-name:parameter-value

  8. 如果一个查询参数具有多个值,请按字母顺序将所有值进行排序,然后以逗号分隔列表的形式包括这些值:

    parameter-name:parameter-value-1,parameter-value-2,parameter-value-n

  9. 在每个名称/值对之后附加换行符 (\n)。

记住以下规则以构造规范化资源字符串:

  • 避免在查询参数的值中使用换行符 (\n)。如果必须使用换行符,请确保它不会影响规范化资源字符串的格式。

  • 避免在查询参数值中使用逗号。

下面是一些示例,演示可基于给定请求 URI 构造的签名字符串 CanonicalizedResource 部分:


Get Container Metadata
   GET http://myaccount.blob.core.windows.net/mycontainer?restype=container&comp=metadata 
CanonicalizedResource:
    /myaccount/mycontainer\ncomp:metadata\nrestype:container

List Blobs operation:
    GET http://myaccount.blob.core.windows.net/container?restype=container&comp=list&include=snapshots&include=metadata&include=uncommittedblobs
CanonicalizedResource:
    /myaccount/mycontainer\ncomp:list\ninclude:metadata,snapshots,uncommittedblobs\nrestype:container

2009-09-19 共享密钥 Lite 和表服务格式

对于所有版本的表服务,此格式支持共享密钥和共享密钥 Lite;对于 2009-09-19 版本的 Blob 和队列服务以及 2014-02-14 版本的文件服务,此格式支持共享密钥 Lite。此格式与用于先前版本的存储服务的格式相同。按照如下格式构造 CanonicalizedResource 字符串:

  1. 以空字符串 ("") 开头,随后追加一个正斜杠 (/),再接拥有待访问资源的帐户的名称。

  2. 附加资源的编码 URI 路径。如果请求 URI 找到了资源的一个组件,则附加相应的查询字符串。该查询字符串应该包括问号和 comp 参数(例如 ?comp=metadata)。查询字符串中不应该包括其他任何参数。

要对签名进行编码,请对 UTF-8 编码的签名字符串调用 HMAC-SHA256 算法,并将结果编码为 Base64 格式。使用以下格式(显示为伪代码):

Signature=Base64(HMAC-SHA256(UTF8(StringToSign)))

另请参阅

显示:
© 2014 Microsoft