簡體   English   中英

AWS身份驗證V4簽名失敗; 生成簽名時我哪里出錯了?

[英]AWS authentication V4 signature failure; where am I going wrong in generating the signature?

我正在使用下面的Ruby代碼生成表單(將帶有從AWS控制台下載的憑證的CSV文件作為參數傳遞給CSV文件)。 如果我使用此表單提交文件, The request signature we calculated does not match the signature you provided. Check your key and signing method.得到The request signature we calculated does not match the signature you provided. Check your key and signing method. The request signature we calculated does not match the signature you provided. Check your key and signing method. 我已經從http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-ruby復制了簽名代碼。 我看過Amazon MWS-計算的請求簽名與提供的簽名不匹配,並且s3“簽名不匹配”客戶端發布jquery-file-upload ,但是這些似乎不適用於我的情況。 我要去哪里錯了?

#!/usr/bin/env ruby

require 'nokogiri'
require 'csv'
require 'ostruct'
require 'base64'
require 'json'
require 'openssl'

header = nil
data = nil
CSV.foreach(ARGV[0]) do |row|
  if header.nil?
    header = row.collect{|c| c.strip.gsub(/\s/, '') }
  else
    data = row
  end
end
creds = OpenStruct.new(Hash[*(header.zip(data).flatten)])

bucket = 'zotplus'
region = 'eu-central-1'
service = 's3'
dateStamp = Time.now.strftime('%Y%m%d')

policy = {
  'expiration' => '2029-01-01T00:00:00Z',
  'conditions' => [
    {'bucket' => bucket},
    ['starts-with', '$key', 'uploads/'],
    {'acl' => 'private'},
    {'success_action_redirect' => 'http://zotplus.github.io/submitted.html'},
    ['starts-with', '$Content-Type', 'multipart/form-data'],
    ['content-length-range', 0, 1048576],
    {'x-amz-date' => "#{dateStamp}T000000Z"},
    {'x-amz-credential' => "#{creds.AccessKeyId}/#{dateStamp}/#{region}/#{service}/aws4_request"}
  ]
}

form = {}
%w{acl success_action_redirect bucket x-amz-date x-amz-credential}.each{|eq|
  form[eq] = policy['conditions'].detect{|c| c.is_a?(Hash) && c[eq] }[eq]
}
form['key'] = policy['conditions'].detect{|c| c.is_a?(Array) && c[0,2] = ['starts-with', '$key']}[2] + '${filename}'

policy_string = Base64.encode64(policy.to_json).gsub("\n","")

kDate    = OpenSSL::HMAC.digest('sha256', "AWS4" + creds.SecretAccessKey, dateStamp)
kRegion  = OpenSSL::HMAC.digest('sha256', kDate, region)
kService = OpenSSL::HMAC.digest('sha256', kRegion, service)
kSigning = OpenSSL::HMAC.digest('sha256', kService, 'aws4_request')

signature = Base64.encode64(OpenSSL::HMAC.digest('sha256', kSigning, policy_string)).gsub("\n","")

form['policy'] = policy_string
form['x-amz-signature'] = signature
form['x-amz-algorithm'] = 'AWS4-HMAC-SHA256'

builder = Nokogiri::HTML::Builder.new do |doc|
  doc.html {
    doc.head {
      doc.title {
        doc.text 'submit file'
      }
      doc.meta('http-equiv' => "Content-Type", content: "text/html; charset=UTF-8")
    }

    doc.body {
      doc.form(action: "http://zotplus-964ec2b7-379e-49a4-9c8a-edcb20db343f.s3.amazonaws.com/", method: "post", enctype: "multipart/form-data") {
        form.each_pair{|k, v|
          doc.input(type: "hidden", name: k, value: v)
        }

        doc.text 'File: '
        doc.input(type: "file", name: "file")
        doc.input(type: "submit", name: "submit", value: "Upload to Amazon S3")
      }
    }
  }
end
puts builder.to_html

好的,事實證明策略簽名不應該使用base64編碼,而只能以十六進制摘要形式輸出。 對於那些同樣遇到難題的人,最終的結果是:

#!/usr/bin/env ruby

require 'json'
require 'base64'
require 'openssl'
require 'csv'
require 'ostruct'
require 'nokogiri'

algorithm = 'AWS4-HMAC-SHA256'
service = 's3'
requestType = 'aws4_request'
successStatus = '201'
bucket = 'zotplus-964ec2b7-379e-49a4-9c8a-edcb20db343f'
region = 'eu-central-1'
acl = 'private'

header = nil
data = nil
CSV.foreach(ENV['ZOTPLUSAWSCREDENTIALS']) do |row|
  if header.nil?
    header = row.collect{|c| c.strip.gsub(/\s/, '') }
  else
    data = row
  end
end
creds = OpenStruct.new(Hash[*(header.zip(data).flatten)])

date = Time.now.strftime('%Y%m%dT%H%M%SZ')
shortDate = date.sub(/T.*/, '')
credentials = [ creds.AccessKeyId, shortDate, region, service, requestType ].join('/')

policy = Base64.encode64({
  'expiration' => (Time.now + (60*60*24*365*30)).strftime('%Y-%m-%dT%H:%M:%SZ'), # 30 years from now
  'conditions' => [
    {'bucket' => bucket},
    {'acl' => acl},
    ['starts-with', '$key', ''],
    ['starts-with', '$Content-Type', ''],
    {'success_action_status' => successStatus},
    {'x-amz-credential' => credentials},
    {'x-amz-algorithm' => algorithm},
    {'x-amz-date' => date},
    ['content-length-range', 0, 1048576],
  ]
}.to_json).gsub("\n","")

signingKey = ['AWS4' + creds.SecretAccessKey, shortDate, region, service, requestType].inject{|key, data| OpenSSL::HMAC.digest('sha256', key, data) } 

form = OpenStruct.new({
  action: "http://#{bucket}.#{service}-#{region}.amazonaws.com",
  fields: [ # order matters!
    {key: '${filename}'},
    {'Content-Type': 'text/plain'},
    {acl: acl},
    {success_action_status: successStatus},
    {policy: policy},
    {'x-amz-algorithm': algorithm},
    {'x-amz-credential': credentials},
    {'x-amz-date': date},
    {'x-amz-signature': OpenSSL::HMAC.hexdigest('sha256', signingKey, policy)}
  ]
})

################################################

builder = Nokogiri::HTML::Builder.new do |doc|
  doc.html {
    doc.head {
      doc.meta(charset: 'utf-8')
      doc.title { doc.text 'Upload' }
    }
    doc.body {
      doc.form(action: form.action, method: 'POST', enctype: "multipart/form-data") {
        form.fields.each{|field|
          field.each_pair{|name, value|
            doc.input(type: 'hidden', name: name, value: value)
          }
        }
        doc.input(type: 'file', name: 'file')
        doc.input(type: 'submit', value: 'Save')
      }
    }
  }
end
puts builder.to_html

是的,它是有效的:DI這樣嘗試過

def index
access_key = 'YOUR_ACCESS_KEY'
secret_key = 'YOUR_SECRET_KEY'
time = Time.now.utc
date_stamp = time.strftime("%Y%m%d")
region_name = 'ap-south-1'
key_date    = hmac_digest('sha256', "AWS4" + secret_key, date_stamp)
key_region  = hmac_digest('sha256', key_date, region_name)
key_service = hmac_digest('sha256', key_region, 's3')
key_signing = hmac_digest('sha256', key_service, "aws4_request")
algorithm = 'AWS4-HMAC-SHA256'
amzdate = time.strftime('%Y%m%dT%H%M%SZ')
credential_scope = access_key + '/' + date_stamp + '/ap-south-1/s3/aws4_request'
policy = generate_policy(credential_scope, algorithm, amzdate)
signature = OpenSSL::HMAC.hexdigest('sha256', key_signing, policy)
render json: { policy: policy, signature: signature, key: access_key, date: amzdate, credentials: credential_scope, algorithm: algorithm }
end
def generate_policy(credential_scope, algorithm, amzdate)
Base64.encode64({
  'expiration' => (Time.now + (60 * 60 * 24 * 365 * 30)).strftime('%Y-%m-%dT%H:%M:%SZ'), # 30 years from now
  'conditions' => [
    { 'bucket' => 'adcreation-m' },
    { 'acl' => 'public-read' },
    ['starts-with', '$key', ''],
    ['starts-with', '$Content-Type', ''],
    { 'success_action_status' => '201' },
    { 'x-amz-credential' => credential_scope },
    { 'x-amz-algorithm' => algorithm },
    { 'x-amz-date' => amzdate },
    ['content-length-range', 0, 256000000]
  ]
}.to_json).delete("\n")
end

def hmac_digest(digest, key, data)
 OpenSSL::HMAC.digest(digest, key, data)
end

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM