这个 API 签名请求方法安全吗?

AJB*_*AJB 5 api digital-signature hmac node.js

我正在认证为我JSON-RPC API和我的当前工作的策略是使用通过发送请求签约POSTSSL

我想知道是否有人可以看到我没有使用以下签名方法考虑的任何漏洞。

客户端和服务器之间的所有通信都是通过POST发送的请求完成的SSLhttpAPI 服务器会直接拒绝不安全的请求。

依赖关系

var uuid = require('node-uuid');
var crypto = require('crypto');
var moment = require('moment');
var MyAPI = require('request-json').newClient('https://api.myappdomain.com');
Run Code Online (Sandbox Code Playgroud)

依赖链接:node-uuid , crypto , moment , request-json

瓦尔斯

var apiVersion = '1.0';
var publicKey = 'MY_PUBLIC_KEY_UUID';
var secretKey = 'MY_SECRET_KEY_UUID';
Run Code Online (Sandbox Code Playgroud)

请求对象

var request = {
    requestID : uuid.v4(),
    apiVersion : apiVersion,
    nonce : uuid.v4(),
    timestamp : moment.utc( new Date() ),
    params : params
}
Run Code Online (Sandbox Code Playgroud)

签名

var signature = crypto.createHmac('sha512',secretKey).update(JSON.stringify(request)).digest('hex');
Run Code Online (Sandbox Code Playgroud)

有效载荷打包(通过POSTover以明文形式发送SSL

var payload = {
    request: request,
    publicKey : publicKey,
    signature : signature
}
Run Code Online (Sandbox Code Playgroud)

结果有效负载 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",
}
Run Code Online (Sandbox Code Playgroud)

POST 请求

MyAPI.post('/', payload, function(response){
    /// Handle any errors ...
    /// Do something with the result ...
    /// Inspect the request you sent ...
});
Run Code Online (Sandbox Code Playgroud)

服务器端

然后在服务器端发生以下情况来验证请求:

  1. PUBLIC_KEY用于SECRET_KEY在数据库中查找。
  2. SECRET_KEY用于request从有效负载创建对象的 HMAC 。
  3. signature负载中发送的哈希request与服务器上创建的对象的哈希进行比较。如果它们匹配,我们继续验证timestamp.
  4. 鉴于我们现在可以信任timestamp明文request对象中发送的内容,因为它包含在signature从客户端发送的散列中,timestamp如果请求太旧,则评估并拒绝身份验证。否则,请求被认证。

据我所知,这是一种用于签名和身份验证请求的安全方法SSL。这样对吗?

在此先感谢您的帮助。

JSON 属性顺序更新

使用时的属性顺序JSON.stringify基本上是随机的,这可能会导致签名不匹配。

由于 JSONrequest对象中属性的顺序,在过去几周使用此签名过程,我没有遇到任何哈希不匹配问题。我相信这是因为我只在request计算客户端哈希之前将对象文字字符串化一次。然后,该request对象采用 JSON 格式作为payload. 一旦被服务器接收到,哈希是直接从有效载荷中接收到的 JSON 对象创建的,没有JSON.stringify调用第二个方法,所以签名总是匹配的,因为属性的顺序是由客户端确定的一次。我会继续研究这个,因为它似乎是一个弱点,如果不是安全问题。

Ale*_*Ten 3

JSON.stringify不保证属性的顺序。例如,对象

{
  a: 1,
  b: 2
}
Run Code Online (Sandbox Code Playgroud)

可以通过两种方式序列化:{"a":1,"b":2}{"b":2,"a":1}。从 JSON 的角度来看,它们是相同的,但它们会导致不同的 HMAC。

成像,用于签名您JSON.stringify生成的第一个表格,但用于检查第二个表格的签名。尽管签名有效,但您的签名检查将失败。