Javascript 正在验证Node.js中的HMAC-SHA256签名
我正在尝试使用一个简单的Python客户端对Node.js服务器验证HMAC-SHA256签名,该客户端对Python服务器进行验证。由于某些原因,我无法在节点中正确验证它Javascript 正在验证Node.js中的HMAC-SHA256签名,javascript,node.js,validation,authentication,hmac,Javascript,Node.js,Validation,Authentication,Hmac,我正在尝试使用一个简单的Python客户端对Node.js服务器验证HMAC-SHA256签名,该客户端对Python服务器进行验证。由于某些原因,我无法在节点中正确验证它 ## # client.py ## import json import time from urllib import error from urllib import request import hmac from hashlib import sha256 USER = 'testuser' KEY = 'xxwM
##
# client.py
##
import json
import time
from urllib import error
from urllib import request
import hmac
from hashlib import sha256
USER = 'testuser'
KEY = 'xxwMXEqOGiY2TssVZ9hvOB4x6EVW3RW75hjAKEai4UBlxG0ts8Js8dsWOzDvAVq4'
if __name__ == '__main__':
now = int(time.time())
payload = {'firstname': 'john', 'lastname': 'doe'}
payload_json = json.dumps(payload)
payload_bytes = bytes(payload_json, 'utf-8')
sig = hmac.new(bytes(KEY, 'utf-8'), b'', sha256)
sig.update(bytes(str(now), 'utf-8'))
sig.update(payload_bytes)
signature = sig.hexdigest()
headers = {
'Authorization': '{}:{}'.format(USER, signature),
'timestamp': str(now),
'Content-Type': 'application/json',
}
req = request.Request('http://localhost:8080/', payload_bytes, headers, method='POST')
try:
with request.urlopen(req) as response:
response_code, response_reason, r = response.code, response.reason, response.read()
except error.HTTPError as e:
response_code, response_reason, r = e.code, e.reason, e
print('RESPONSE: {} {}\n{}'.format(response_code, response_reason, r))
在Python中,我(成功地)验证请求,如下所示:
##
# snippet from server.py
##
user = {'user': 'testuser', 'secret_key': 'xx...'} # usually queries the database
if user:
check_sig = hmac.new(bytes(user['secret_key'], 'utf8'), b'', sha256)
check_sig.update(bytes(headers['TIMESTAMP'], 'utf-8')) # timestamp sent in request header
check_sig.update(data) # data is binary json-formatted string
check_signature = check_sig.hexdigest()
if hmac.compare_digest(check_signature, hmac_hash): # hmac_hash is user's signature from request
time_diff = int(time.time()) - int(headers['TIMESTAMP'])
if 0 <= time_diff <= 30:
print('kewl!')
return True
/*
* server.js
*/
var restify = require('restify');
var crypto = require('crypto');
var bufferEq = require('buffer-equal-constant-time');
var _ = require('lodash');
var nconf = require('nconf').file({file: 'config.json'});
var server = restify.createServer();
server.use(restify.acceptParser(server.acceptable));
// server.use(require(path.join(__dirname, 'auth'))());
server.use(restify.dateParser());
server.use(restify.queryParser());
server.use(restify.jsonp());
server.use(restify.gzipResponse());
server.use(restify.bodyParser());
// server.use(restify.requestExpiry());
server.use(restify.throttle({
burst: 100,
rate: 50,
ip: true,
overrides: {
'192.168.1.1': {
rate: 0, // unlimited
burst: 0
}
}
}));
server.use(restify.conditionalRequest());
server.use(function authenticate(req, res, next) {
console.log('checking auth...');
var user = req.headers.authorization.split(':')[0];
var key = req.headers.authorization.split(':')[1];
console.log(key);
var credentials = nconf.get('Security:Users');
var dbUser = _.filter(credentials, {user: user}).pop();
var checkSignature = crypto.createHmac('sha256', dbUser.key)
.update(req.headers.timestamp, 'utf8')
.update(JSON.stringify(req.body), 'utf8')
.digest('hex');
console.log(checkSignature);
if (!bufferEq(new Buffer(checkSignature), new Buffer(key))) {
return next(new restify.UnauthorizedError('Authorization error.'));
}
return next();
});
function respond(req, res, next) {
res.send('hello!');
next();
}
server.get('/', respond);
server.post('/', respond);
server.listen(8080, function() {
console.log('%s listening at %s', server.name, server.url);
});
…但是比较签名总是失败的
这是在节点中创建HMAC-SHA256签名的正确方法吗?我一直在跟踪,这看起来很简单…你能发布签名的两个最终结果吗?@GiveMeAllYourCats好吧,因为HMAC是用当前时间戳生成的,所以我可以为你提供一堆SHA256字符串,它们在Python中是相同的,在Node.js中总是不同的:)技术上,在Python中,我收到200个OK响应,在节点401中收到未经授权的响应。如果您认为打印/记录我在请求中收到的其他资料或其他任何东西会有所帮助,我很乐意与您分享,请告诉我您到底需要什么;)好的,我想要输出的原因是编码。你注意到什么奇怪的事情了吗?@GiveMeAllYourCats在Python客户端,我正在发送utf-8,由TestRing编码,在Python服务器中(在我的示例中为
data
)接收完全相同的类型和结构。在节点服务器上,req.body
作为JS对象接收,我随后将其转换为字符串(JSON.stringify(req.body)
),甚至强制utf-8编码。我试图更改节点端的缓冲区
比较,但问题是它总是会失败,因为重新生成的签名与用户发送的签名不同(都是SHA256字符串,但它们只是不匹配:)@GiveMeAllYourCats例如,在上一次运行中,发送的签名客户端是4f8e40a4bf5eb06565e135ad26d1eb430a215759778fba4ed6a6905b66d307d51
,节点服务器上重新生成的签名客户端是64fe27f4582a8ad3287f7399ba2ff92d5002dbd5b50c95172ab08c4950a54d0
。。。