我正在为我的 JSON-RPC API
进行身份验证,我目前的工作策略是使用通过 POST
通过 SSL
发送的签名请求.
我想知道是否有人可以通过以下签名方法看到我没有考虑到的任何漏洞。
客户端和服务器之间的所有通信都是通过通过 SSL
发送的 POST
请求完成的。不安全的 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');
依赖链接: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');
有效负载打包(通过 SSL
上的 POST
作为明文发送)
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
对象的哈希值进行比较。如果它们匹配,我们将继续验证时间戳
。 - 鉴于我们现在可以信任在明文
request
对象中发送的timestamp
,因为它包含在从客户端发送的signature
哈希中,timestamp
被评估,如果请求太旧,身份验证将被拒绝。否则,请求通过身份验证。
据我所知,这是一种通过 SSL
发送签名和身份验证请求的安全方法。这是正确的吗?
在此先感谢您的帮助。
JSON Property Order 更新
The order of properties when using
JSON.stringify
is essentially random, which could cause signature mis-matches.
在过去几周使用这个签名过程,由于 JSON request
对象中的属性顺序,我没有遇到任何哈希不匹配问题。我相信这是因为我只对 request
对象文字进行了一次字符串化,就在计算客户端哈希之前。然后,request
对象以 JSON 格式作为 payload
的一部分。服务器接收到哈希值后,直接从负载中接收到的 JSON 对象创建哈希值,不会调用第二个 JSON.stringify
方法,因此签名始终匹配,因为属性的顺序已确定一次, 由客户。我会继续研究这个问题,因为它看起来是一个弱点,如果不是安全问题的话。
最佳答案
JSON.stringify
不保证属性的顺序。例如对象
{
a: 1,
b: 2
}
可以用两种方式序列化:{"a":1,"b":2}
或 {"b":2,"a":1}
。从 JSON 的角度来看,它们是相同的,但它们会产生不同的 HMAC。
想象一下,对于签名,您的 JSON.stringify
生成第一种形式,但用于检查签名的第二种形式。尽管签名有效,但您的签名检查将失败。
关于node.js - 这个 API 签名请求方法安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23820128/