Azure Blob SAS令牌生成遇Signature did not match错误求助
Azure Blob SAS令牌生成签名不匹配问题排查
问题背景
需用JavaScript生成Azure Blob的SAS令牌,编写的代码生成URL后在浏览器访问时触发AuthenticationFailed错误,提示Signature did not match。代码将用于ServiceNow业务规则,需排查修复。
原代码
var CryptoJS = require("crypto-js/core") var blobAccount = 'ACCOUNTNAME'; var blobContainer = 'CONTAINERNAME/PATH_TO_FILE'; var sasToken = ''; var storageAccountKey = 'KEY2'; // 计算过期时间 var currentDate = new Date(); var expiration = new Date(currentDate.getTime() + (100 * 365 * 24 * 60 * 60 * 1000)); var st = currentDate.toISOString().slice(0,19)+'Z'; var se = expiration.toISOString().slice(0,19)+'Z'; var sv = '2018-11-09'; var sp = 'r'; var sr = 'b'; var canonicalizedResource = "/"+blobAccount+"/"+blobContainer; var stringToSign = sp+'\n'+st+'\n'+se+'\n'+canonicalizedResource+'\n'+sv+'\n'+sr+'\n'+'\n'+'\n'+'\n'+'\n'+'\n'+'\n'+'\n'; var signature = CryptoJS.HmacSHA256(stringToSign, CryptoJS.enc.Base64.parse(storageAccountKey)).toString(CryptoJS.enc.Base64); sasToken = encodeURIComponent(signature)+"&st="+st.replaceAll(':','%3A')+"&se="+se.replaceAll(':','%3A')+"&sv=2018-11-09&sp=r&sr=b" var url = "https://"+blobAccount+".blob.core.windows.net/"+blobContainer+"?"+"sig="+sasToken console.log(sasToken); console.log(url)
错误信息
<Error> <Code>AuthenticationFailed</Code> <Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:1145b24b-201e-005c-3b3b-86f4f3000000 Time:2023-05-14T08:10:23.2762870Z</Message> <AuthenticationErrorDetail>Signature did not match. String to sign used was r 2023-05-14T08:09:57Z 2123-04-20T08:09:57Z /blob/ACCOUNTNAME/CONTAINERNAME/PATH_TO_FILE 2018-11-09 b </AuthenticationErrorDetail> </Error>
问题分析与修复
从错误信息中的String to sign used was可以看出,Azure服务器实际使用的签名字符串和代码中生成的存在核心差异:
1. 核心错误:CanonicalizedResource格式错误
Azure服务器期望的资源路径是/blob/ACCOUNTNAME/CONTAINERNAME/PATH_TO_FILE,但原代码构造的是/ACCOUNTNAME/CONTAINERNAME/PATH_TO_FILE,缺少/blob前缀。针对Blob服务的SAS签名,CanonicalizedResource必须以/blob/<存储账户名>/<资源路径>开头。
2. StringToSign格式不规范
针对API版本2018-11-09,StringToSign的字段顺序和空行必须严格遵循规则,未使用的字段需留空行,不能随意添加或省略。
3. CryptoJS模块不完整
原代码仅导入crypto-js/core,缺少HmacSHA256和Base64编码的模块支持,可能导致签名计算错误。
4. URL编码方式不可靠
手动替换:为%3A不如使用encodeURIComponent通用可靠。
修复后的代码
// 导入完整CryptoJS模块,确保包含HmacSHA256和Base64功能 var CryptoJS = require("crypto-js"); var blobAccount = 'ACCOUNTNAME'; var blobContainer = 'CONTAINERNAME/PATH_TO_FILE'; var sasToken = ''; var storageAccountKey = 'KEY2'; // 计算过期时间 var currentDate = new Date(); var expiration = new Date(currentDate.getTime() + (100 * 365 * 24 * 60 * 60 * 1000)); var st = currentDate.toISOString().slice(0,19)+'Z'; var se = expiration.toISOString().slice(0,19)+'Z'; var sv = '2018-11-09'; var sp = 'r'; var sr = 'b'; // 修正CanonicalizedResource格式,添加/blob前缀 var canonicalizedResource = `/blob/${blobAccount}/${blobContainer}`; // 严格按照2018-11-09版本的StringToSign格式构造,未使用字段留空行 var stringToSign = [ sp, st, se, canonicalizedResource, "", // Identifier(留空) "", // IPAddress(留空) "", // Protocol(留空) sv, sr, "", // SnapshotTime(留空) "", // EncryptionScope(留空) "", // CacheControl(留空) "", // ContentDisposition(留空) "", // ContentEncoding(留空) "", // ContentLanguage(留空) "" // ContentType(留空) ].join('\n'); // 生成签名 var signature = CryptoJS.HmacSHA256(stringToSign, CryptoJS.enc.Base64.parse(storageAccountKey)).toString(CryptoJS.enc.Base64); // 拼接SAS令牌,使用encodeURIComponent统一编码特殊字符 sasToken = `sig=${encodeURIComponent(signature)}&st=${encodeURIComponent(st)}&se=${encodeURIComponent(se)}&sv=${sv}&sp=${sp}&sr=${sr}`; // 构造完整访问URL var url = `https://${blobAccount}.blob.core.windows.net/${blobContainer}?${sasToken}`; console.log(sasToken); console.log(url);
关键注意事项
- CanonicalizedResource必须准确:不同Azure服务(Blob/File/Queue)的CanonicalizedResource前缀不同,Blob服务必须加
/blob。 - StringToSign格式严格匹配API版本:每个API版本的签名字符串格式可能有差异,需严格遵循对应版本的规则。
- 确保CryptoJS模块完整:若使用模块化导入,需单独引入
crypto-js/hmac-sha256和crypto-js/enc-base64。 - 参数编码要彻底:所有含特殊字符的参数(如st、se)都需用
encodeURIComponent编码,避免URL解析错误。
内容的提问来源于stack exchange,提问作者imchandan
相关产品推荐
相关产品推荐

