Azure Blob下载SAS Token验证失败:签名不匹配问题求助
Azure Blob SAS URL生成出现「Signature did not match」问题排查
我用Ruby生成Azure Blob的SAS URL,示例URL如下:
https://anasstoragetest2023.blob.core.windows.net/telestream/test.mov?sp=r&st=2023-03-14T20:23:04Z&se=2023-03-18T20:23:04Z&spr=https&sv=2021-12-02&sr=b&sig=6wpeYAlfpnGLPtk5PcIe/P+0q+XeLkIT6XLFR6uY5Os=
遇到「Signature did not match」错误,错误详情:
<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:0daa3721-e01e-0002-3049-58f5bf000000 Time:2023-03-16T20:55:10.7515529Z</Message> <AuthenticationErrorDetail>Signature did not match. String to sign used was r 2023-03-14T20:52:54Z 2023-03-18T20:52:54Z /blob/anasstoragetest2023/telestream/test.mov https 2021-12-02 b </AuthenticationErrorDetail> </Error>
我的代码输出的签名字符串和错误日志里的完全一致:
String to sign: r 2023-03-14T20:52:54Z 2023-03-18T20:52:54Z /blob/anasstoragetest2023/telestream/test.mov https 2021-12-02 b
尝试过Azure官方的SAS生成器,生成的token同样报这个错,代码如下:
blob_path = "/blob/#{account_name}/#{container_name}/#{blob_name}" signature = Azure::Storage::Common::Core::Auth::SharedAccessSignature.new(account_name, account_key) sas_token = signature.generate_service_sas_token(blob_path, service: 'b', resource: 'b') puts "\nCreated SAS token: #{sas_token}" url = "https://#{account_name}.blob.core.windows.net/#{container_name}/#{blob_name}?#{sas_token}" puts "\nCreated URL: #{url}"
以下是我自己写的Ruby代码,试过Ruby 3.1.3和2.6.8版本,依赖通过gem install azure-storage-blob安装,求解决:
def generate_blob_url(account_name, account_key, container_name, blob_name) start_time = Time.now days = 60*60*24*2 signed_permissions = "r" signed_start = (start_time - days).utc.iso8601 signed_expiry = (start_time + days).utc.iso8601 canonicalized_resource = "/blob/#{account_name}/#{container_name}/#{blob_name}" signed_identifier = "" signed_ip = "" signed_protocol = "https" signed_version = "2021-12-02" # "2018-11-09" signed_resource = "b" signed_snapshottime = "" rscc = "" rscd = "" rsce = "" rscl = "" rsct = "" string_to_sign = signed_permissions + "\n" + signed_start + "\n" + signed_expiry + "\n" + canonicalized_resource + "\n" + signed_identifier + "\n" + signed_ip + "\n" + signed_protocol + "\n" + signed_version + "\n" + signed_resource + "\n" + signed_snapshottime + "\n" + rscc + "\n" + rscd + "\n" + rsce + "\n" + rscl + "\n" + rsct puts "\nString to sign: #{string_to_sign.gsub("\n", " ")}" sig = Base64.strict_encode64(OpenSSL::HMAC.digest('sha256', account_key, string_to_sign)) token = "sp=#{signed_permissions}&st=#{signed_start}&se=#{signed_expiry}&spr=#{signed_protocol}&sv=#{signed_version}&sr=#{signed_resource}&sig=#{sig}" puts "\nGenerated token: #{token}" url = "https://#{account_name}.blob.core.windows.net/#{container_name}/#{blob_name}?#{CGI.escape(token)}" end
解决建议
- 解码账户密钥后再计算签名
Azure存储账户密钥是Base64编码格式,直接用字符串计算HMAC会导致签名错误,需要先解码为原始字节:
decoded_account_key = Base64.decode64(account_key) sig = Base64.strict_encode64(OpenSSL::HMAC.digest('sha256', decoded_account_key, string_to_sign))
- 避免SAS Token整体编码
你当前用CGI.escape(token)会把Base64签名里的+、/等字符转义成%2B、%2F,Azure无法识别转义后的字符,应该直接拼接token:
url = "https://#{account_name}.blob.core.windows.net/#{container_name}/#{blob_name}?#{token}"
严格控制签名字符串格式
确保签名字符串里的空参数(如signed_identifier、signed_ip)仅保留单个换行符,没有多余空格。代码中gsub("\n", " ")只是用于打印显示,实际生成的string_to_sign要严格按照参数顺序用\n分隔。验证官方生成器的密钥传入方式
使用官方生成器时,同样要确保传入的account_key是解码后的原始字节,避免直接使用Base64字符串。
内容的提问来源于stack exchange,提问作者anode84
相关产品推荐
相关产品推荐

