我为部分跟随this very good blog post by Riyad Kalla的项目创建了一个简单的RESTful API。现在,我已经在Stack Overflow上阅读了几十个类似的问题,但我似乎找不到安全问题的答案。
简而言之,我的要求是这样的:
我担心有人使用我的服务可以获取公共API密钥(通过嗅探网络流量),然后简单地通过他们的浏览器使用AJAX直接向开发人员的服务器提交客户端最初要做的相同请求。因此,恶意用户可以作为合法用户进行身份验证,并使用其他秘密API密钥访问API。
我会尝试举一个具体的例子。通常我会这样做:
但我害怕:
我缺少什么或者这只是RESTful API游戏的一部分?
更新:我自愿省略任何形式的时间戳验证,以保持简单,只关注身份验证问题。
更新2:我已为流程添加了$_SERVER['HTTP_REFERER']
验证。这里的目标是客户端必须与请求一起发送引用者,并且它必须与API侧数据库中列出的引用者匹配。不幸的是,HTTP引用可以很容易伪造。这是另一个安全级别,但仍然不完美。
更新3:我更改了服务器端代码,将引荐来源设置为远程IP地址。这会强制发送到我的服务器的每个请求使用秘密API密钥进行哈希处理,最终使用原始请求IP地址到达API服务器。然后可以验证此IP并且请求可以通过。我相信它有可能伪造$_SERVER['REMOTE_ADDR']
,但它比伪造$_SERVER['HTTP_REFERER']
更复杂......我想还是不完美。
更新4 :根据这些帖子:How to fake $_SERVER['REMOTE_ADDR'] variable?和https://serverfault.com/questions/90725/are-ip-addresses-trivial-to-forge,伪造$_SERVER['REMOTE_ADDR']
虽然很难实现。但是,由于您无法控制伪造网络,因此无法接收伪造请求的响应。该请求可以成功验证,但其响应不会落入恶意手中。
答案 0 :(得分:4)
使用HMAC,您走在正确的轨道上。但是,还有两件事可以使您的应用程序更安全。
答案 1 :(得分:0)
我发现阻止其他脚本使用公共API密钥并向服务器端HMAC哈希脚本发送请求的解决方案是发送原始请求者的身份以及请求。我正在使用$_SERVER['REMOTE_ADDR']
来确定原始请求者的身份,因为它更难伪造,伪造它通常意味着他们不会得到回应。
/* $this as a class that handles requests */
// Build hash and include timestamp
$this->vars['timestamp'] = time();
$this->vars['hash'] = hash_hmac('sha1', http_build_query($this->vars).$this->vars['token'], API_SECRET);
// Send request to API
curl_setopt_array($this->curl, array(
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => $url,
CURLOPT_POST => $this->method == 'post' ? 1 : NULL,
CURLOPT_POSTFIELDS => $this->method == 'post' ? $this->vars : NULL,
CURLOPT_CONNECTTIMEOUT => 15,
CURLOPT_TIMEOUT => 15,
CURLOPT_REFERER => $_SERVER['REMOTE_ADDR'], // Referer here!
CURLOPT_MAXREDIRS => 3,
CURLOPT_HTTPGET => $this->method == 'get' ? true : false
));
一旦发送,API不仅会检查数据库中的秘密API密钥,还会检查$_SERVER['HTTP_REFERER']
是否被列为允许!这也允许API基于每个用户接受服务器。