由于授权标头,Azure Blob 存储 403 身份验证失败

Posted

技术标签:

【中文标题】由于授权标头,Azure Blob 存储 403 身份验证失败【英文标题】:Azure Blob Storage 403 Authentication Failed Due To Authorization Header 【发布时间】:2021-09-24 09:22:03 【问题描述】:

问题

我已将一组图像 (blob) 上传到私有 Azure Blob 存储帐户,但是当我尝试访问它们时,我遇到了以下错误。


    GET https://<account-name>.blob.core.windows.net/<container-name>/<blob-name> 403 (Server failed 
    to authenticate the request. Make sure the value of Authorization header is formed correctly 
    including the signature.)

我上传这些数据没有任何问题,因为这是使用 Django 应用程序通过服务器端完成的。我希望能够使用客户端 javascript 成功检索此上传的 blob 数据。

背景

我已彻底阅读并实施了 Microsoft Azure 文档中的步骤,以通过使用 Shared Keys 授权访问我的私人帐户。这包括从构建我的签名字符串到使用 HMAC SHA-256 算法对这些数据进行哈希处理的所有内容,如上面的链接中所述。

我在 Docker 容器上运行所有东西,除了客户端基于 Vue 的接口试图调用 Get Blob API 端点,如下所示。

最小可重现示例

引发此错误的代码如下:

// Add imports
const crypto = require('crypto');
const axios = require('axios');

// Set Azure blob storage data
const account = "<azure-blob-storage-private-account-name>"
const version = "2020-04-08"
const blob = "<blob-name>"
const container = "<container-name>"
const blob_uri = `https://$account.blob.core.windows.net/$container/$blob`;
const today = new Date().toGMTString();
      
// Construct signature string
const CanonicalisedHeaders = `x-ms-date:$today\nx-ms-version:$version\n`;
const CanonicalisedResource = `/$account/$container/$blob`;
const StringToSign = `GET\n\n\n\n\n\n\n\n\n\n\n\n` + CanonicalisedHeaders + CanonicalisedResource;

// Hash string using HMAC Sha-256 and encode to base64
const key = "<shared-access-key-in-base64>";
const utf8encoded = Buffer.from(key, 'base64').toString('utf8');
const signature = crypto.createHmac('sha256', utf8encoded).update(StringToSign).digest("base64");

// Construct the headers and invoke the API call
const blob_config = 
  headers: 
    "Authorization": `SharedKey $account:$signature`,
    "x-ms-date": today,
    "x-ms-version": version
  

await axios.get(blob_uri, blob_config)
  .then((data) => console.log(data))
  .catch((error) => console.log(error.message));

我尝试过的

我尝试了以下方法,但都没有帮助我解决手头的问题。

    更新了 CORS 设置以避免与 CORS 相关的 403 禁止访问问题。 重新生成了我的密钥和连接字符串。 检查了本地计算机和 Docker 容器上的 DateTime 设置,以确保它们处于正确的 GMT 时间。 检查了我的签名字符串的组件(规范化的标头、资源等)是根据here 定义的规则构造的。 阅读类似的 *** 和 Azure 论坛帖子以寻找解决方案。

【问题讨论】:

这个“钥匙”是从哪里来的?是连接字符串中的“AccountKey”还是为容器生成的 SAS?无论我使用哪个键,我都会收到相同的错误。我也试过 SAS 的这个“sig”键 @AhmadKarim 我使用key 来指代“存储帐户密钥”,您可以按照此处所述访问:docs.microsoft.com/en-us/azure/storage/common/…。在这种情况下,您的任何一个存储帐户密钥都应该可以使用。我希望这会有所帮助:) 【参考方案1】:

请尝试更改以下代码行:

const utf8encoded = Buffer.from(key, 'base64').toString('utf8');
const signature = crypto.createHmac('sha256', utf8encoded).update(StringToSign).digest("base64");

const keyBuffer = Buffer.from(key, 'base64');
const signature = crypto.createHmac('sha256', keyBuffer).update(StringToSign).digest("base64");

我认为您不需要将密钥缓冲区转换为 UTF8 编码的字符串。

其他几件事:

    考虑到您在浏览器中使用它,当您将存储密钥暴露给用户时存在巨大的安全风险。 您是否有理由直接使用 REST API 而不是使用Azure Storage Blob SDK? 在基于浏览器的环境中,您应该使用基于Shared Access Signature 的授权,而不是基于Shared Access Key 的授权。

【讨论】:

删除.toString('utf8') 修复了403 状态码错误:我现在正在接收数据!谢谢你:) 不过我有点惊讶,因为documentation 表明共享密钥应该从base64? 解码。在第 1 点,我将把密钥存储在 .env 文件中。关于第 2 点,我以前不知道这个库:我现在将它用于我的应用程序!关于第 3 点,围绕 SAS 的最佳实践是什么? SAS 应该多久重新生成一次? I'm a bit surprised though, because the documentation shows that the shared key should be decoded from base64 - 您正在这样做,但随后您使用 Buffer.from(key, 'base64').toString('utf8'); 将其转换为 UTF8 编码字符串,这导致了问题。 2, I didn't know about this library before: I will use it for my app now! - 是的。 SDK 非常有用和方便,可以为您实现 REST API。 On point 3, what is the best practice surrounding SAS? How often should SAS's be regenerated? - docs.microsoft.com/en-us/azure/storage/common/…。 HTH。

以上是关于由于授权标头,Azure Blob 存储 403 身份验证失败的主要内容,如果未能解决你的问题,请参考以下文章

REST Api 使用访问密钥到 Azure Blob 存储

创建 Azure 存储 Blob 容器时出现错误 403(已启用存储防火墙

Azure Blob 存储上传错误:(403)禁止

Azure 使用 REST api 和托管标识创建 blob 容器 - 403 错误

当用于 Blob 存储的 Azure REST API 使用具有前缀或标记的查询字符串时获取 403

将 Cache-Control 和 Expires 标头添加到 Azure 存储 Blob