node.js - 这个 API 签名请求方法安全吗?

标签 node.js api digital-signature hmac

我正在为我的 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 ...
});

服务器端

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

  1. PUBLIC_KEY 用于在数据库中查找SECRET_KEY
  2. SECRET_KEY 用于从负载中创建 request 对象的 HMAC。
  3. 将有效载荷中发送的signature 哈希值与在服务器上创建的request 对象的哈希值进行比较。如果它们匹配,我们将继续验证时间戳
  4. 鉴于我们现在可以信任在明文 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/

相关文章:

javascript - 使用 javascript 在 Rails 中自动返回 API 请求值

java - 获取机器的所有快照 (VirtualBox Java API)

jquery - 使用 jQuery 从 Wikipedia API 检索 JSON 数据

php - 如何在 PHP 中对文件进行数字签名

Node.js 加密货币使用 tron 公共(public)地址创建 ecdh

javascript - 多个异步函数调用

macos - OSX 上的 NPM 全局安装位置

node.js - 解析服务器查询结果中未定义的列值

java - SHA1 和 RSA 与 java.security.Signature 对比 MessageDigest 和 Cipher

javascript - RSA登录python并在JS中验证