Downloading AWS S3 Browser Using HTTP POST Gives Invalid Signature

I am working on a site where users should be able to upload video files to AWS. To avoid unnecessary traffic, I would like the user to load directly into AWS (and not through the API server). In order not to disclose my secret key in JavaScript, I am trying to create a signature in the API. However, he tells me when I try to download that the signature does not match.

To generate the signature, I used http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-UsingHTTPPOST.html

On the backend, I run C #.

I create a signature using

string policy = $@"{{""expiration"":""{expiration}"",""conditions"":[{{""bucket"":""dennisjakobsentestbucket""}},[""starts-with"",""$key"",""""],{{""acl"":""private""}},[""starts-with"",""$Content-Type"",""""],{{""x-amz-algorithm"":""AWS4-HMAC-SHA256""}}]}}";

which generates the following

{"expiration":"2016-11-27T13:59:32Z","conditions":[{"bucket":"dennisjakobsentestbucket"},["starts-with","$key",""],{"acl":"private"},["starts-with","$Content-Type",""],{"x-amz-algorithm":"AWS4-HMAC-SHA256"}]}

http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html (I base64 ). , .

, AWS.

static byte[] HmacSHA256(String data, byte[] key)
{
    String algorithm = "HmacSHA256";
    KeyedHashAlgorithm kha = KeyedHashAlgorithm.Create(algorithm);
    kha.Key = key;

    return kha.ComputeHash(Encoding.UTF8.GetBytes(data));
}

static byte[] GetSignatureKey(String key, String dateStamp, String regionName, String serviceName)
{
    byte[] kSecret = Encoding.UTF8.GetBytes(("AWS4" + key).ToCharArray());
    byte[] kDate = HmacSHA256(dateStamp, kSecret);
    byte[] kRegion = HmacSHA256(regionName, kDate);
    byte[] kService = HmacSHA256(serviceName, kRegion);
    byte[] kSigning = HmacSHA256("aws4_request", kService);

    return kSigning;
}

:

byte[] signingKey = GetSignatureKey(appSettings["aws:SecretKey"], dateString, appSettings["aws:Region"], "s3");
byte[] signature = HmacSHA256(encodedPolicy, signingKey);

dateString yyyymmdd

POST JavaScript

let xmlHttpRequest = new XMLHttpRequest();
let formData = new FormData();
formData.append("key", "<path-to-upload-location>");
formData.append("acl", signature.acl); // private
formData.append("Content-Type", "$Content-Type");
formData.append("AWSAccessKeyId", signature.accessKey);
formData.append("policy", signature.policy); //base64 of policy
formData.append("x-amz-credential", signature.credentials); // <accesskey>/20161126/eu-west-1/s3/aws4_request
formData.append("x-amz-date", signature.date);
formData.append("x-amz-algorithm", "AWS4-HMAC-SHA256");
formData.append("Signature", signature.signature);
formData.append("file", file);

xmlHttpRequest.open("post", "http://<bucketname>.s3-eu-west-1.amazonaws.com/");
xmlHttpRequest.send(formData);

UTF8 , AWS. , . , , 403

The request signature we calculated does not match the signature you provided. Check your key and signing method.

AWS "s3: Get *", "s3: Put *"

- , ?

: . , AWS . 0xFF!= 0xff AWS. .

+4
2

, Signature Version 4, , 2- ... , .

formData.append("AWSAccessKeyId", signature.accessKey);

V2. .

formData.append("x-amz-credential", signature.credentials); // <accesskey>/20161126/eu-west-1/s3/aws4_request

V4. AWS . , , , X-Amz-Credential.

formData.append("x-amz-algorithm", "AWS4-HMAC-SHA256");

, , X-Amz-Algorithm. (, , , ).

formData.append("Signature", signature.signature);

. X-Amz-Signature. V4 , . V2 - base64.

V4 aws- , , , ..., , , . , , , .

; JSON- (- JSON ), JSON- base64- . , , , , ​​ , , - , , - : , base64 , , , .

, Signature V2 S3, Signature V4 S3-, , , V2, .

, The request signature we calculated does not match the signature you provided. Check your key and signing method , . . , , , AWS , -, .

+4

POST HTTP-, :

require 'rest-client'

class S3Uploader
  def initialize
    @options = {
      aws_access_key_id: "ACCESS_KEY",
      aws_secret_access_key: "ACCESS_SECRET",
      bucket: "BUCKET",
      acl: "private",
      expiration: 3.hours.from_now.utc,
      max_file_size: 524288000
    }
  end

  def fields
    {
      :key => key,
      :acl => @options[:acl],
      :policy => policy,
      :signature => signature,
      "AWSAccessKeyId" => @options[:aws_access_key_id],
      :success_action_status => "201"
    }
  end

  def key
    @key ||= "temp/${filename}"
  end

  def url
    "http://#{@options[:bucket]}.s3.amazonaws.com/"
  end

  def policy
    Base64.encode64(policy_data.to_json).delete("\n")
  end

  def policy_data
    {
      expiration: @options[:expiration],
      conditions: [
        ["starts-with", "$key", ""],
        ["content-length-range", 0, @options[:max_file_size]],
        { bucket: @options[:bucket] },
        { acl: @options[:acl] },
        { success_action_status: "201" }
      ]
    }
  end

  def signature
    Base64.encode64(
      OpenSSL::HMAC.digest(
        OpenSSL::Digest.new("sha1"),
        @options[:aws_secret_access_key], policy
      )
    ).delete("\n")
  end
end

uploader = S3Uploader.new
puts uploader.fields
puts uploader.url

begin
  RestClient.post(uploader.url, uploader.fields.merge(file: File.new('51bb26652134e98eae931fbaa10dc3a1.jpeg'), :multipart => true))
rescue RestClient::ExceptionWithResponse => e
  puts e.response
end
0

Source: https://habr.com/ru/post/1662022/


All Articles