Node.js 此API签名请求方法安全吗?
我正在为我的Node.js 此API签名请求方法安全吗?,node.js,api,digital-signature,hmac,Node.js,Api,Digital Signature,Hmac,我正在为我的JSON-rpcapi进行身份验证,我当前的工作策略是使用通过POSToverSSL发送的签名请求 我想知道是否有人可以看到我在使用以下签名方法时没有考虑到的任何漏洞 客户端和服务器之间的所有通信都是通过POST通过SSL发送的请求完成的。不安全的http请求被API服务器彻底拒绝 依赖关系 var uuid = require('node-uuid'); var crypto = require('crypto'); var moment = require('moment');
JSON-rpcapi
进行身份验证,我当前的工作策略是使用通过POST
overSSL
发送的签名请求
我想知道是否有人可以看到我在使用以下签名方法时没有考虑到的任何漏洞
客户端和服务器之间的所有通信都是通过POST
通过SSL
发送的请求完成的。不安全的http
请求被API服务器彻底拒绝
依赖关系
var uuid = require('node-uuid');
var crypto = require('crypto');
var moment = require('moment');
var MyAPI = require('request-json').newClient('https://api.myappdomain.com');
var apiVersion = '1.0';
var publicKey = 'MY_PUBLIC_KEY_UUID';
var secretKey = 'MY_SECRET_KEY_UUID';
依赖项链接:
Vars
var uuid = require('node-uuid');
var crypto = require('crypto');
var moment = require('moment');
var MyAPI = require('request-json').newClient('https://api.myappdomain.com');
var apiVersion = '1.0';
var publicKey = 'MY_PUBLIC_KEY_UUID';
var secretKey = 'MY_SECRET_KEY_UUID';
请求对象
var request = {
requestID : uuid.v4(),
apiVersion : apiVersion,
nonce : uuid.v4(),
timestamp : moment.utc( new Date() ),
params : params
}
{
"request" : {
"requestID" : "687de6b4-bb02-4d2c-8d3a-adeacd2d183e",
"apiVersion" : "1.0",
"nonce" : "eb7e4171-9e23-408a-aa2b-cd437a78af22",
"timestamp" : "2014-05-23T01:36:52.225Z",
"params" : {
"class" : "User"
"method" : "getProfile",
"data" : {
"id" : "SOME_USER_ID"
}
}
},
"publicKey" : "PUBLIC_KEY",
"signature" : "7e0a06b560220c24f8eefda1fda792e428abb0057998d5925cf77563a20ec7b645dacdf96da3fc57e1918950719a7da70a042b44eb27eabc889adef95ea994d1",
}
MyAPI.post('/', payload, function(response){
/// Handle any errors ...
/// Do something with the result ...
/// Inspect the request you sent ...
});
签名
var signature = crypto.createHmac('sha512',secretKey).update(JSON.stringify(request)).digest('hex');
有效负载打包(通过POST
通过SSL
以明文形式发送)
结果有效负载JSON文档
var request = {
requestID : uuid.v4(),
apiVersion : apiVersion,
nonce : uuid.v4(),
timestamp : moment.utc( new Date() ),
params : params
}
{
"request" : {
"requestID" : "687de6b4-bb02-4d2c-8d3a-adeacd2d183e",
"apiVersion" : "1.0",
"nonce" : "eb7e4171-9e23-408a-aa2b-cd437a78af22",
"timestamp" : "2014-05-23T01:36:52.225Z",
"params" : {
"class" : "User"
"method" : "getProfile",
"data" : {
"id" : "SOME_USER_ID"
}
}
},
"publicKey" : "PUBLIC_KEY",
"signature" : "7e0a06b560220c24f8eefda1fda792e428abb0057998d5925cf77563a20ec7b645dacdf96da3fc57e1918950719a7da70a042b44eb27eabc889adef95ea994d1",
}
MyAPI.post('/', payload, function(response){
/// Handle any errors ...
/// Do something with the result ...
/// Inspect the request you sent ...
});
发布请求
var request = {
requestID : uuid.v4(),
apiVersion : apiVersion,
nonce : uuid.v4(),
timestamp : moment.utc( new Date() ),
params : params
}
{
"request" : {
"requestID" : "687de6b4-bb02-4d2c-8d3a-adeacd2d183e",
"apiVersion" : "1.0",
"nonce" : "eb7e4171-9e23-408a-aa2b-cd437a78af22",
"timestamp" : "2014-05-23T01:36:52.225Z",
"params" : {
"class" : "User"
"method" : "getProfile",
"data" : {
"id" : "SOME_USER_ID"
}
}
},
"publicKey" : "PUBLIC_KEY",
"signature" : "7e0a06b560220c24f8eefda1fda792e428abb0057998d5925cf77563a20ec7b645dacdf96da3fc57e1918950719a7da70a042b44eb27eabc889adef95ea994d1",
}
MyAPI.post('/', payload, function(response){
/// Handle any errors ...
/// Do something with the result ...
/// Inspect the request you sent ...
});
服务器端
var signature = crypto.createHmac('sha512',secretKey).update(JSON.stringify(request)).digest('hex');
然后在服务器端执行以下操作以验证请求:
PUBLIC\u KEY
用于在数据库中查找SECRET\u KEY
SECRET\u KEY
用于从有效负载创建请求
对象的HMAC签名
散列与服务器上创建的请求
对象的散列进行比较。如果它们匹配,我们将继续验证时间戳
请求
对象中发送的时间戳
,因为它包含在从客户机发送的签名
散列中,因此时间戳
将被评估,如果请求太旧,身份验证将被拒绝。否则,请求将通过身份验证SSL
发送的签名和身份验证请求的安全方法。这是正确的吗
提前感谢您的帮助
更新JSON属性顺序
使用JSON.stringify
时,属性的顺序基本上是随机的,这可能会导致签名不匹配
在过去的几周里,使用这个签名过程,我没有遇到任何由于JSON
request
对象中属性的顺序而导致的哈希错误匹配问题。我相信这是因为在计算客户端哈希之前,我只对请求
对象文本进行了一次字符串化。然后,请求
对象以JSON格式作为有效负载的一部分。一旦服务器接收到,哈希将直接从有效负载中接收的JSON对象创建,没有第二个调用的JSON.stringify
方法,因此签名始终匹配,因为属性的顺序由客户端确定一次。不过,我会继续研究这个问题,因为它似乎是一个弱点,如果不是安全问题的话。JSON.stringify
不能保证属性的顺序。例如,对象
{
a: 1,
b: 2
}
可以通过两种方式进行序列化:{“a”:1,“b”:2}
或{“b”:2,“a”:1}
。从JSON的角度来看,它们是相同的,但它们将导致不同的HMAC
图像,用于签名您的JSON.stringify
生成第一个表单,但用于检查签名第二个表单。您的签名检查将失败,尽管签名是有效的。我在这里看到的唯一可疑的东西是其他评论中发布的JSON.stringify,但您可以使用:
这样,您就可以得到一个确定性散列来进行签名。我看到的主要流程是JSON.stringify不保证为对象提供相同的输出。谢谢你的评论,阿列克西。但是,对象中属性的顺序并不重要。事实上,这就是使用JSON对象作为有效负载形式的全部原因,以避免在request
方法中需要有序参数。啊,我现在明白你的意思了。回调函数的结果
错误
请求
参数在本文中是一个误传。我来编辑。