Raj Raj -4 years ago 519
PHP Question

aws s3 signature does not match -pre signed url

I want to upload files to aws s3 through pre signed url. I used this github project https://github.com/JoernBerkefeld/s3SignedUpload but It shows error while uploading.

<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>
The request signature we calculated does not match the signature you provided. Check your key and signing method.
</Message>
<AWSAccessKeyId>AKIAI2DLTCOXU5255TMQ</AWSAccessKeyId>
<StringToSign>
AWS4-HMAC-SHA256 20160810T174345Z 20160810/ap-south-1/s3/aws4_request a63f9ead869c1fb4d06fa1169458b87978d86fd44348144636c2e0cb2c10cdf5
</StringToSign>
<SignatureProvided>
ae7bd98265316de85f3c55e539ca9bdb5934620428a7924b9404a9403dd9d4d2
</SignatureProvided>
<StringToSignBytes>
41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 0a 32 30 31 36 30 38 31 30 54 31 37 34 33 34 35 5a 0a 32 30 31 36 30 38 31 30 2f 61 70 2d 73 6f 75 74 68 2d 31 2f 73 33 2f 61 77 73 34 5f 72 65 71 75 65 73 74 0a 61 36 33 66 39 65 61 64 38 36 39 63 31 66 62 34 64 30 36 66 61 31 31 36 39 34 35 38 62 38 37 39 37 38 64 38 36 66 64 34 34 33 34 38 31 34 34 36 33 36 63 32 65 30 63 62 32 63 31 30 63 64 66 35
</StringToSignBytes>
<CanonicalRequest>
GET /logo.jpg Content-Type=image%2Fjpeg&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAI2DLTCOXU5255TMQ%2F20160810%2Fap-south-1%2Fs3%2Faws4_request&X-Amz-Date=20160810T174345Z&X-Amz-Expires=1800&X-Amz-SignedHeaders=Host host:indiastreetz.s3.ap-south-1.amazonaws.com host UNSIGNED-PAYLOAD
</CanonicalRequest>
<CanonicalRequestBytes>
47 45 54 0a 2f 6c 6f 67 6f 2e 6a 70 67 0a 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3d 69 6d 61 67 65 25 32 46 6a 70 65 67 26 58 2d 41 6d 7a 2d 41 6c 67 6f 72 69 74 68 6d 3d 41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 26 58 2d 41 6d 7a 2d 43 72 65 64 65 6e 74 69 61 6c 3d 41 4b 49 41 49 32 44 4c 54 43 4f 58 55 35 32 35 35 54 4d 51 25 32 46 32 30 31 36 30 38 31 30 25 32 46 61 70 2d 73 6f 75 74 68 2d 31 25 32 46 73 33 25 32 46 61 77 73 34 5f 72 65 71 75 65 73 74 26 58 2d 41 6d 7a 2d 44 61 74 65 3d 32 30 31 36 30 38 31 30 54 31 37 34 33 34 35 5a 26 58 2d 41 6d 7a 2d 45 78 70 69 72 65 73 3d 31 38 30 30 26 58 2d 41 6d 7a 2d 53 69 67 6e 65 64 48 65 61 64 65 72 73 3d 48 6f 73 74 0a 68 6f 73 74 3a 69 6e 64 69 61 73 74 72 65 65 74 7a 2e 73 33 2e 61 70 2d 73 6f 75 74 68 2d 31 2e 61 6d 61 7a 6f 6e 61 77 73 2e 63 6f 6d 0a 0a 68 6f 73 74 0a 55 4e 53 49 47 4e 45 44 2d 50 41 59 4c 4f 41 44
</CanonicalRequestBytes>
<RequestId>78A21E02C733E895</RequestId>
<HostId>
rBd5ZQBuMyjouFZbSavDcFX4n4fEuqSj8aZuCQyw9rChSSpZkBFZjd8CXqog2OWPMX96OSIuFmo=
</HostId>
</Error>


Answers I found at stackoverflow doesn't fix my solution.Please tell me how to fix or where to find the error.

public function getSignedUrl($filename, $mime) {
if(!$filename) {
return $this->error('filename missing');
}
if(!$mime) {
return $this->error('mime-type missing');
}
$final_filename = $this->get_file_name($filename);
try {
$signedUrl = $this->client->getCommand('PutObject', array(
'Bucket' => $this->bucket,
'Key' => $this->folder.$final_filename,
'ContentType' => $mime,
'Body' => '',
'ContentMD5' => false
))->createPresignedUrl('+30 minutes');
} catch (S3Exception $e) {
echo $e->getMessage() . "\n";
}

$signedUrl .= '&Content-Type='.urlencode($mime);
return array('url'=>$signedUrl);
}

Answer Source

I used PHP inbuilt hash functions to pre-sign a upload and then upload the file with POST.

When a user clicks an upload button, it will get a pre-signed data from presign_url and then begin upload to aws.

 $.ajax({
                url: 'presign_url.php',
                type: 'post',
                dataType: 'json',
                success: function (data) {
                   send_img(png,image_size,data); /* append this data with your post data. I pass the data to my image uploading function.data contains presigned data(image name,file size,format and other amazon credentials )*/
                },
                data: {}
            });

//presign_url.php

 <?php
    $access_key         = "XXXXXXXXXXXX"; //Access Key
    $secret_key         = "xyzxyzxyzxyz"; //Secret Key
    $my_bucket          = "bucketname"; //bucket name
    $region             = "your region"; //bucket region ex:-ap-south-1
    $success_redirect   = "http://localhost/info";// your redirect url
    $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI']; //URL to which the client is redirected upon success (currently self) 
    $allowd_file_size   = "1048579"; //1 MB allowed Size

    //dates
    $short_date         = gmdate('Ymd'); //short date
    $iso_date           = gmdate("Ymd\THis\Z"); //iso format date
    $expiration_date    = gmdate('Y-m-d\TG:i:s\Z', strtotime('+1 hours')); //policy expiration 1 hour from now

    $filename=uniqid().".jpg"; // file name to be which file is saved.
    //POST Policy required in order to control what is allowed in the request
    //For more info http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html
    $policy = utf8_encode(json_encode(array(
                        'expiration' => $expiration_date,  
                        'conditions' => array(
                            array('acl' => 'public-read'),  
                            array('bucket' => $my_bucket), 
                            array('success_action_redirect' => $success_redirect),
                            array('starts-with', '$key','user/'),
                            array('content-length-range', '1', $allowd_file_size), 
                            array('x-amz-credential' => $access_key.'/'.$short_date.'/'.$region.'/s3/aws4_request'),
                            array('x-amz-algorithm' => 'AWS4-HMAC-SHA256'),
                            array('X-amz-date' => $iso_date)
                            )))); 

    //Signature calculation (AWS Signature Version 4)   
    //For more info http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html  
    $kDate = hash_hmac('sha256', $short_date, 'AWS4' . $secret_key, true);
    $kRegion = hash_hmac('sha256', $region, $kDate, true);
    $kService = hash_hmac('sha256', "s3", $kRegion, true);
    $kSigning = hash_hmac('sha256', "aws4_request", $kService, true);
    $signature = hash_hmac('sha256', base64_encode($policy), $kSigning);

    $arr=array();
    $arr["u"]="http://$my_bucket.s3.amazonaws.com/";
    $arr["k"]=$filename;
    $arr["a"]="public-read";
    $arr["ac"]="$access_key/$short_date/$region/s3/aws4_request";
    $arr["aa"]="AWS4-HMAC-SHA256";
    $arr["ad"]=$iso_date;
    $arr["p"]=base64_encode($policy);
    $arr["as"]="$signature";
    $arr["sar"]="$success_redirect";
    $arr["us"]="user/";
    echo json_encode($arr);
    ?>
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download