我正在为JSON-RPC API
进行身份验证,目前的工作策略是使用POST
通过SSL
发送的已签名请求。
我想知道是否有人可以通过以下签名方法看到我没有考虑到的任何漏洞。
客户端和服务器之间的所有通信都是通过POST
发送的SSL
请求完成的。 API服务器完全拒绝了不安全的http
请求。
依赖关系
var uuid = require('node-uuid');
var crypto = require('crypto');
var moment = require('moment');
var MyAPI = require('request-json').newClient('https://api.myappdomain.com');
依赖关系链接:node-uuid,crypto,moment,request-json
瓦尔
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
}
特征
var signature = crypto.createHmac('sha512',secretKey).update(JSON.stringify(request)).digest('hex');
有效负载包装(通过POST
通过SSL
以明文形式发送)
var payload = {
request: request,
publicKey : publicKey,
signature : signature
}
结果有效负载JSON文档
{
"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",
}
POST请求
MyAPI.post('/', payload, function(response){
/// Handle any errors ...
/// Do something with the result ...
/// Inspect the request you sent ...
});
服务器端
然后在服务器端发生以下情况以验证请求:
PUBLIC_KEY
用于查找数据库中的SECRET_KEY
。SECRET_KEY
用于从有效负载创建request
对象的HMAC。signature
哈希值与服务器上创建的request
对象的哈希值进行比较。如果匹配,我们将继续验证timestamp
。timestamp
对象中发送的request
,因为它包含在客户端发送的signature
哈希中,因此会对timestamp
进行评估如果请求太旧,则拒绝身份验证。否则,请求已通过身份验证。据我所知,这是一种通过SSL
发送签名和身份验证请求的安全方法。这是对的吗?
提前感谢您的帮助。
更新JSON Property Order
使用
JSON.stringify
时的属性顺序基本上是随机的,这可能会导致签名不匹配。
在过去几周内使用此签名过程,由于JSON request
对象中属性的顺序,我没有遇到任何哈希不匹配问题。我相信这是因为我只在计算客户端哈希之前对request
对象文字进行一次字符串化。然后,request
对象是JSON格式,作为payload
的一部分。一旦被服务器接收,就直接从有效载荷中接收的JSON对象创建散列,没有调用第二个JSON.stringify
方法,因此签名总是匹配,因为属性的顺序由客户端确定一次。我会继续关注这一点,因为它似乎是一个弱点,如果不是安全问题。
答案 0 :(得分:3)
JSON.stringify
不保证属性的顺序。例如,对象
{
a: 1,
b: 2
}
可以通过两种方式序列化:{"a":1,"b":2}
或{"b":2,"a":1}
。它们从JSON的角度来看是相同的,但它们会导致不同的HMAC。
成像,用于签名,JSON.stringify
生成第一个表单,但用于检查第二个签名。虽然签名有效,但您的签名检查将失败。
答案 1 :(得分:2)
我在这里看到的唯一可疑的东西就是在其他评论中发布的JSON.stringify,但你可以使用:
https://www.npmjs.com/package/json-stable-stringify
通过这种方式,您可以为您的标志设置确定性散列。