虽然亚马逊提供了sdk,使用SDK会自动帮你计算签名。如果你能使用SDK 请一定使用SDK。
但是目标平台为嵌入式平台(非Linux)只支持C接口,很多库移植成本过高,为了使用S3服务,我们应该首选restfulAPI 这种方案。这就涉及到了自己实现AWS V4签名的问题。

前排资料:
我们可以阅读AWS SDK(nodejs) 源码签名实现进行参考验证:
aws-nodejs-sample\node_modules\aws-sdk\lib\signers 及aws-nodejs-sample\node_modules\aws-sdk\libutil.js
AWSV4签名文档:
https://docs.aws.amazon.com/zh_cn/AmazonS3/latest/API/sig-v4-authenticating-requests.html

1 AWS v4签名

与Amazon S3的每次交互都是经过身份验证。本节介绍使用AWS Signature Version 4算法的请求认证。S3目前只支持V4验证。

1.1认证方法:

HTTP授权标头 - 使用HTTP Authorization标头是验证Amazon S3请求的最常用方法。所有Amazon S3 REST操作(使用POST请求的基于浏览器的上传除外)都需要此标头。本文使用的是这种方式。且为单个区块传输方式。

1.2 签名环境

在单个区块中传输有效负载(AWS签名版本4)
当在单个块中传输有效载荷时,可以选择将有效载荷散列包含在签名计算中,称为带符号有效载荷(如果不包含它,有效载荷将被视为无符号)。即是否计算待上传文件hash值。
我们选择的是第二种:无符号有效负载选项 - UNSIGNED-PAYLOAD在构建规范请求时包含文字字符串,并x-amz-content-sha256在向S3发送请求时将相同的值设置为 标题值。不计算负载hash值。即x-amz-content-sha256 设置为UNSIGNED-PAYLOAD。

签名环境总结:
1 用于s3
2 单个区块上传文件
3 不计算有效负载hash

1.3签名理论

要计算签名,您首先需要一个字符串来签名。然后HMAC-SHA256使用签名密钥计算要签名的字符串的散列。下图说明了该过程,包括您为签名创建的字符串的各个组件
当Amazon S3收到验证请求时,它会计算签名,然后将其与您在请求中提供的签名进行比较。因此,您必须使用Amazon S3使用的相同方法来计算签名。以协议形式签署请求的过程称为规范化。
即你的操作必须完全符合标准,因为AWS 也会按照标准计算一次,相同就成功。
签名流程图:

所需要的基础方法:

2 实际操作

我们可以从图中看出Authorization的得到有3部分组成,且是顺序获取 前一个是后一个的前置条件。
1 Canonical Request
2 StringToSign
3 Signature
下面将分别介绍
本文验证用了些全局变量:

var accessKeyId = ' ';
var secretAccessKey= ' ';
var region='us-east-1';
var serviceName='s3';
var algorithm = 'AWS4-HMAC-SHA256';
var v4Identifier = 'aws4_request';

2.1 Canonitcal Requet

Canonitcal Requet 有下面六个部分组成

<HTTPMethod>\n
<CanonicalURI>\n
<CanonicalQueryString>\n
<CanonicalHeaders>\n
<SignedHeaders>\n
<HashedPayload>

2.1.1HTTPMethod

HTTPMethod 是HTTP方法之一,例如GET,PUT,HEAD和DELETE。

2.1.2 CanonicalURI

CanonicalURI是URI的绝对路径组件的URI编码版本 - 任何以跟在域名后面的“/”开头,直到字符串末尾或问号字符。
如http://s3.amazonaws.com/examplebucket/myphoto.jpg ,CanonicalURI即为/examplebucket/myphoto.jpg 。

2.1.3 CanonicalQueryString

CanonicalQueryString指定URI编码的查询字符串参数。您可以单独对URI进行编码名称和值。即url的query参数。比较复杂,详情可参见文档。
因为我们是S3操作不带query参数,按文档说明:
如果URI不包含’?’,则请求中没有查询字符串,并且将规范查询字符串设置为空字符串(“”)。您仍然需要包含“\ n”。

2.1.4 CanonicalHeaders

CanonicalHeaders是请求标题及其值的列表。单独的标题名称和值对由换行符(“\ n”)分隔。标题名称必须小写。您必须按字母顺序排列标题名称以构建字符串

Lowercase(<HeaderName1>)+":"+Trim(<value>)+"\n"
Lowercase(<HeaderName2>)+":"+Trim(<value>)+"\n"
...
Lowercase(<HeaderNameN>)+":"+Trim(<value>)+"\n"

sample:

'content-md5:ZwmeZ+R9fiKB4KNgjnCUbw==\nhost:xxxxxx.s3.amazonaws.com\nx-amz-content-sha256:UNSIGNED-PAYLOAD\nx-amz-date:20180313T054459Z\n'

实现code:

function canonicalHeaderValues(values) {return values.replace(/\s+/g, ' ').replace(/^\s+|\s+$/g, '');
}
function canonicalHeaders(request) {var headers = [];for(var i in request.header){headers.push([i, request.header[i]]);}headers.sort(function (a, b) {return a[0].toLowerCase() < b[0].toLowerCase() ? -1 : 1;});var parts = [];for(var i in headers){var key = headers[i][0].toLowerCase();var value =  headers[i][1];parts.push(key + ':' + canonicalHeaderValues(value.toString()));}return parts.join('\n');}

2.1.6 HashedPayload

HashedPayload 是请求有效负载的SHA256哈希值的十六进制值。我们选择不计算有效负载hash值 直接给 UNSIGNED-PAYLOAD

2.1.7 代码实现

function canonicalString(request) {var parts = [];//pathname = uriEscapePath(request.pathname);parts.push(request.method);parts.push(request.pathname);parts.push("");parts.push(canonicalHeaders(request) + '\n');parts.push(signedHeaders(request));parts.push('UNSIGNED-PAYLOAD');console.info(parts);return parts.join('\n');}

Request 参数

var header ={'host' : 'xxxxxx.s3.amazonaws.com','x-amz-content-sha256':'UNSIGNED-PAYLOAD','x-amz-date':date,'content-md5':md5
}
var req ={header : header,pathname : '/xxxx/test02.jpg',method : 'PUT',bodyhash: 'UNSIGNED-PAYLOAD'
}

date参数:

var date = (new Date()).toISOString().replace(/\-|:|\.\d\d\d/g,""); (后面所有的date都是这个)
20180313T054459Z   (注意时区)
Md5参数:
const hash = crypto.createHash('md5');
hash.update(bitmap);
var md5 = hash.digest('base64');
console.info(md5);

打印结果( console.info(parts)

[ 'PUT','/xxxx/test02.jpg','','content-md5:ZwmeZ+R9fiKB4KNgjnCUbw==\nhost:xxxxxx.s3.amazonaws.com\nx-amz-content-sha256:UNSIGNED-PAYLOAD\nx-amz-date:20180313T054459Z\n','content-md5;host;x-amz-content-sha256;x-amz-date','UNSIGNED-PAYLOAD' ]

2.2 StringToSign

本节概述创建要签名的字符串。对于一步一步的说明,请参阅任务2:创建一个字符串来登录在AWS一般参考。
要签名的字符串是以下字符串的串联:

"AWS4-HMAC-SHA256" + "\n" +
timeStampISO8601Format + "\n" +
<Scope> + "\n" +
Hex(SHA256Hash(<CanonicalRequest>))

2.2.1 AWS4-HMAC-SHA256

常量字符串AWS4-HMAC-SHA256指定您正在使用的哈希算法HMAC-SHA256

2.2.2 timeStampISO8601Format

这timeStamp是ISO 8601格式的当前UTC时间(例如, 20130524T000000Z)
前面我们已经获取到了

2.2.3 Scope

Scope将生成的签名绑定到特定日期,AWS区域和服务
sample:

20180313/us-east-1/s3/aws4_request

code:

  function createScope(date, region, serviceName) {return [date.substr(0, 8),region,serviceName,'aws4_request'].join('/');}function credentialString(datetime) {return createScope(datetime.substr(0, 8),region,serviceName);}

2.2.4 Hex(SHA256Hash())

将2.1中得到的CanonicalRequest 进行sha256 在转成16进制
code:

sha256(string, 'hex'); //基础方法已经提供

2.2.5 代码实现

Code:

function stringToSign(datetime, request) {var parts = [];parts.push('AWS4-HMAC-SHA256');parts.push(datetime);parts.push(credentialString(datetime));console.info(canonicalString(request));parts.push(hexEncodedHash(canonicalString(request)));console.info(parts);return parts.join('\n');}

打印结果:

[ 'AWS4-HMAC-SHA256','20180313T054459Z','20180313/us-east-1/s3/aws4_request','1ae0b089a24ef398ef1204efe29fee5b7c762e43f35165b0c4bc74xxxxxxxxx' ]

2.3 Signature

我们可以在图中看出获得Signature 需要signingKey和StringToSign。
HMAC-SHA256(SigningKey, StringToSign)

2.3.1 signingKey

在AWS签名版本4中,不是使用您的AWS访问密钥签署请求,而是首先创建一个签名密钥,该密钥的范围限定为特定的区域和服务。
签名密匙得到:

DateKey              = HMAC-SHA256("AWS4"+"<SecretAccessKey>", "<YYYYMMDD>")
DateRegionKey        = HMAC-SHA256(<DateKey>, "<aws-region>")
DateRegionServiceKey = HMAC-SHA256(<DateRegionKey>, "<aws-service>")
SigningKey           = HMAC-SHA256(<DateRegionServiceKey>, "aws4_request")

code:

function getSigningKey(credentials,date,region,service,shouldCache)
{var kDate =hmac('AWS4' + secretAccessKey,date,'buffer');var kRegion = hmac(kDate, region, 'buffer');var kService = hmac(kRegion, service, 'buffer');var signingKey = hmac(kService, v4Identifier, 'buffer');return signingKey;
}

2.3.2 Signature

HMAC-SHA256(SigningKey, StringToSign)

code:

function signature(datetime, request) {var signingKey = getSigningKey(0,datetime.substr(0, 8),region,serviceName);return hmac(signingKey, stringToSign(datetime, request), 'hex');
}

打印结果:

6553bf9cab10de458afb093543b8154903307ec96a7e2d84696c38941aaad1aa

2.4 获取Authorization

Authorization由下列值组成:

Authorization: AWS4-HMAC-SHA256
Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request,
SignedHeaders=host;range;x-amz-date,                                                                       ( Canonitcal Requet 已获取)
Signature=fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024 (已得到)

Code:

function authorization(request, datetime) {var parts = [];var credString = credentialString(datetime);parts.push('AWS4-HMAC-SHA256'+ ' Credential=' +accessKeyId + '/' + credString);parts.push('SignedHeaders=' + signedHeaders(request));parts.push('Signature=' + signature(datetime, request));return parts.join(', ');}

打印结果:

AWS4-HMAC-SHA256 Credential=XXXXXXX/20180313/us-east-1/s3/aws4_request, SignedHeaders=content-md5;host;x-amz-content-sha256;x-amz-date, Signature=6553bf9cab10de458afb093543b8154903307ec96a7e2d84696c3xxxxxxxxx

2.5发起s3put请求

var options = {url: 'http://xxxxxxx.s3.us-east-1.amazonaws.com/xxxxx/test02.jpg',headers: { 'content-md5':md5 ,host: 'xxxxxxx.s3.amazonaws.com', 'x-amz-content-sha256':'UNSIGNED-PAYLOAD','x-amz-date':date,Authorization: result},body:bitmap
};request.put(options, function(error, response, body ) {console.log( 'response: ' + response );console.log( 'body: ' + body );
});

AWS S3 V4签名实现(nodejs)相关推荐

  1. AWS s3 V4签名算法

    原创,转载请注明:http://www.jianshu.com/p/a6a02309190f 一.开篇说明: 以下思考方向,是以Android端为出发点(IOS同理) AWS:Amazon Web S ...

  2. 【转】AWS s3 V4签名算法

    转载请注明:http://www.jianshu.com/p/a6a02309190f 一.开篇说明: 以下思考方向,是以Android端为出发点(IOS同理) AWS:Amazon Web Serv ...

  3. aws签名 php,创建亚马逊AWS S3预签名URL PHP - php

    根据此链接http://docs.aws.amazon.com/aws-sdk-php/v2/guide/service-s3.html,我可以轻松地创建一个预签名链接,只需将寿命添加到getObje ...

  4. aws s3 php,Amazon S3 预签名 POSTs 与 AWS SDK for PHP 版本 3 - 适用于 PHP 的 AWS 开发工具包...

    AWS 文档中描述的 AWS 服务或功能可能因区域而异.要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门. 本文属于机器翻译版本.若本译文内容与英语原文存在差异,则一律以英文原文为准. Am ...

  5. php上传照片到s3云服务器,PHP上传文件到AWS S3生成下载文件URL

    * 加载s3客户端 * @return string*/ functionAWS_S3Client(){$ACCESS_KEY_ID = '你的s3 ID';$SECRET_ACCESS_KEY = ...

  6. AWS S3云存储服务

    AWS S3云存储服务 1 S3概念及基础知识 2 S3的基本操作 3 S3数据安全 4 S3数据加密以及命令行CLI 4.1 S3加密工作原理 4.1.1 server端的加密 4.1.2 clie ...

  7. editor 插入图片之后将光标放到右侧_通过vscode插件自动上传剪贴板图片至aws s3

    vscode是我日常所使用的编辑器,包括在写这篇文章的时候.在编辑markdown文档的时候,总会遇到插入图片的问题.所以我就想实现一个简单的vscode插件,在运行时,可以将剪贴板里的图片上传到aw ...

  8. 我们如何使用CircleCI 2.0来构建Angular应用并将其部署到AWS S3

    by Marius Lazar 通过马里乌斯·拉扎尔(Marius Lazar) 我们如何使用CircleCI 2.0来构建Angular应用并将其部署到AWS S3 (How we used Cir ...

  9. aws s3 参与s3game寻找宝藏游戏挑战学习s3对象存储

    参考资料 Pirates S3game workshop http://s3game-level1.s3-website.us-east-2.amazonaws.com/level1.html htt ...

最新文章

  1. mysql根据当前时间删除_从日期时间早于另一项日期时间的Mysql表中删除
  2. java迷宫生成代码_通过深度优先搜索产生的迷宫的Java代码
  3. C语言函数与接口有什么区别?
  4. C语言实现queue队列的算法(附完整源码)
  5. Axure5.1不能输入中文问题.
  6. mysql将查询数据另存
  7. VC++6.0 按F1无法打开 MSDN 的解决办法
  8. [POJ3096]Surprising Strings
  9. wms地图绘制工具_【工具】奇幻风世界地图绘制工具Inkarnate
  10. ASP.NET中的ExecuteNonQuery()方法的用法
  11. 如何将原生PDF转为纯图像Word?
  12. tcp 粘包是怎么产生的?
  13. 阿里巴巴内部面试资料
  14. CSS-DIV页面布局
  15. Matlab/Simulink-Boost电路双闭环仿真搭建
  16. 知识兔课程揭秘跨境电商的大骗局,你有没有被坑过!
  17. splash : mouse_click()方法
  18. 2008年国家公务员面试2月27号真题
  19. [JavaEE] Hibernate OGM
  20. HTML5初学----基础代码案例汇总

热门文章

  1. 免费的配音软件有哪些?推荐这三款配音软件,不再烦恼短视频配音
  2. 计算机怎么游戏教学,游戏教学法在小学计算机教学中的应用
  3. 12V-480V​​​​​​​宽电压电池放电容量测试仪参数说明
  4. echarts 设置地图外边框、地图背景渐变色和地图阴影,增加立体感以及在地图上打点
  5. 20972多媒体操作系统
  6. java手册之字符串操作
  7. unity 图片变纯色填充 变色
  8. 如何使用VB批量采集指定网站上的图片文件以及网页内文字等资源素材
  9. 电子邮件推广的十个原则
  10. php 提权脚本 linux,linux 自动提权perl脚本