You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure Blob Storage:块Blob上传MAC签名不匹配问题排查

问题描述

使用REST API向Azure Blob Storage上传块Blob时,按文档构造待签名字符串后持续收到403错误:

Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.

现有核心代码如下:

待签名字符串构造

$str2sign = "PUT


$blockSize

$blockMimeType





x-ms-blob-type:BlockBlob
x-ms-date:$Date
x-ms-version:2019-12-12
$headerResource
$urlResource";

其中$headerResource为:

x-ms-blob-type:BlockBlob
x-ms-date:$Date
x-ms-version:2019-12-12

$urlResource为:

/$storageAccountname/$containerName/$blobName
blockid:" . urlencode($blockId) . "
comp:block

签名生成

$sig = base64_encode(hash_hmac('sha256', urldecode(utf8_encode($str2sign)), base64_decode($accesskey), true));

授权头与请求头

$authHeader = "SharedKey $storageAccountname:$sig";

$headers = [
  'Authorization: ' . $authHeader,
  'x-ms-date: ' . $Date,
  'x-ms-version: 2019-12-12',
  'Content-Length: ' . strlen($blockList),
  'Content-Type: application/xml',
];

CURL请求

curl_setopt($ch, CURLOPT_URL, $URL);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, $blockList);

$result = curl_exec($ch);

注:其他使用相同认证方式的Blob上传/展示功能可正常运行,例如下载功能的签名构造片段:

// Azure Blob Storage download
$Date = gmdate('D, d M Y H:i:s \G\M\T');

$headerResource = "x-ms-date:$Date
x-ms-version:2019-12-12";
$urlResource = "/$storageAccountname/$containerName/$blobName";

$arraysign = array();
$arraysign[] = 'GET';               /*HTTP Verb*/
$arraysign[] = '';                  /*Content-Encoding*/
$arraysign[] = '';                  /*Content-Language*/
$arraysign[] = '';                  /*Content-Length (include value when zero)*/
$arraysign[] = '';                  /*Content-MD5*/
$arraysign[] = '';                  /*Content-Type*/
$arraysign[] = '';                  /*Date*/
$arraysign[] = '';                  /*If-Modified-Since */
$arraysign[] = '';                  /*If-Match*/
$arraysign[] = '';                  /*If-None-Match*/
排查方向及解决建议
  • 移除待签名字符串中的重复头部字段
    当前$str2sign中已手动写入x-ms-blob-type、x-ms-date、x-ms-version,又追加了$headerResource,导致这些字段被重复计入签名,直接引发验证失败。修正后的$str2sign应只保留一次Canonicalized Headers:

    $str2sign = "PUT
    
    
    $blockSize
    
    $blockMimeType
    
    
    
    
    
    x-ms-blob-type:BlockBlob
    x-ms-date:$Date
    x-ms-version:2019-12-12
    $urlResource";
    
  • 对齐HTTP请求方法与签名中的方法
    签名构造用的是PUT,但CURL默认使用POST(因设置了CURLOPT_POSTFIELDS),需显式指定PUT方法:

    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
    
  • 修正CanonicalizedResource的格式
    查询参数需合并到同一行,用&分隔,而非换行。正确的$urlResource构造:

    $urlResource = "/$storageAccountname/$containerName/$blobName?comp=block&blockid=" . urlencode($blockId);
    
  • 简化签名生成的编码操作
    urldecode(utf8_encode($str2sign))属于冗余操作,待签名字符串无需URL解码,直接使用原始字符串即可:

    $sig = base64_encode(hash_hmac('sha256', $str2sign, base64_decode($accesskey), true));
    
  • 确保Content-Length的准确性
    若$blockList包含多字节字符,strlen()会计算字符数而非字节数,导致长度不匹配。改用mb_strlen()计算字节数:

    'Content-Length: ' . mb_strlen($blockList, '8bit'),
    

内容的提问来源于stack exchange,提问作者LucaSpeedStack

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 19:34:57