我有一个标准的API设置,其中通过使用归属于提供的公钥的私钥散列请求正文并将其与查询字符串中的hash
值进行比较来验证客户端。
例如,请求正文为"THIS IS REQUEST BODY"
,他们会将hash
设置为sha256('THIS IS REQUEST BODY'.PRIVATE_KEY)
,然后服务器会做同样的事情来验证它。
如果请求正文为空,如何保护此身份验证过程?哈希值是私钥的哈希值,然后可以被任何收听流量的人重新用于类似的“空”请求。
我假设唯一的答案是“需要请求主体中的内容”,但也许我错过了一些明显的内容。
答案 0 :(得分:3)
首先,不要HASH(DATA + KEY)
。它有已知的漏洞。这正是HMAC
的设计目标。所以你的哈希值是:
hash = HMAC(sha256, data, privateKey)
现在,处理问题(如何防止重放攻击)的典型方法是为每个请求添加一个随机因子。有几种方法可以做到这一点,但效果很好的方法是基于nonce
的方法。所以:
nonce = random(16)
now = time()
data = api_data + '|' + nonce + '|' + now
hash = HMAC(sha256, data, privateKey)
apiCall = data '&nonce=' + nonce + '&time=' + now + '&sig=' + hash
然后,在接收方,您将跟踪过去30秒内看到的随机数列表。如果你得到一个你见过的,那么拒绝api调用(因为这将是一次重播攻击)。如果你得到的时间超过30秒,请拒绝api电话。
if (now < time() - 30) {
return false;
} else if (nonceExists(nonce)) {
return false;
}
addNonce(nonce);
data = api_data + '|' + nonce + '|' + now
myhash = HMAC(sha256, data, privateKey)
if (myhash == hash) {
return api_data;
}
return false;
然后你可以每隔30秒(在一个cron作业上)或每周清除nonce的数据库,这并不重要。取决于您的API的活跃程度。
这里的关键是你想要跟踪nonce的有效性,否则你很容易受到重播攻击......
答案 1 :(得分:1)
为什么不在请求中使用时间戳。这将使消息独一无二。您可以使用时间同步,也可以使用要在服务器上验证的请求以明文形式发送时间戳。