在安全API通信中使用请求签名时,防止重放攻击?

时间:2012-03-29 18:12:57

标签: php security api signature man-in-the-middle

我一直在阅读API通信证券,并试图找出构建安全API的最佳方法。 我知道OAuth等存在,但我也试图在这个过程中教育自己,而不是依赖图书馆。

基本上我有一个Web服务,用户可以在Web服务中注册API。他们将获得一个配置文件ID和密钥,他们必须使用这些密钥从另一个Web系统构建API请求。

API请求的构建方式与银行方式类似,发送到API的所有输入数据都必须进行排序,哈希计算,然后将哈希发送到服务器,如下所示:

// Profile data
$apiProfile='api123';
$apiSecret='this-is-a-good-day-to-be-a-secret-key';

// Input
$input=array();
$input['name']='Thomas Moore';
$input['profession']='Baker';

// To ensure that the order of variables checked and received is the same on both ends:
ksort($input);

// Using serialize() for simplifying things
// http_build_query() is another option, or just placing values in order
$input['hash']=sha1(serialize($input).$apiSecret); 

// Making a request to URL:
// Using file_get_contents() as an example, would use cURL otherwise
$result=file_get_contents('http://www.example.com/api.php?'.http_build_query($input));

// SERVER CALCULATES COMPARISON HASH BASED ON KNOWN SECRET KEY AND INPUT DATA

这真的很好并且有效。但是!我的问题是潜在的重播攻击。如果某人抢夺了此请求URL,他们可以再次将其发送到服务器,即使他们无法自行更改数据。

现在我已经阅读了一些关于它的事情你应该检查时间或者在请求中添加一次性使用令牌,但我不确定我该怎么做呢?发送带有请求的时间戳是否足够安全? (如果时钟有点同步,接收服务器将确保请求在请求发出的几秒内发起。)

我还可以在混音中添加IP验证,但这些可以改变,并且可能会有些欺骗,对用户来说更麻烦。

我会喜欢这种一次性令牌类型的系统,但我不确定如何在不将令牌生成暴露给完全相同的重放攻击问题的情况下如何做到这一点? (我需要的最后一件事就是允许为中间人提供安全的代币)。

非常欢迎意见和文章,我一直无法找到能够解答我特定问题的材料。 我想说我的API是安全的,而不仅仅是营销说话。

谢谢!

2 个答案:

答案 0 :(得分:3)

您只需要通过安全通道(https)允许令牌交换,并且每条消息都应该有一个唯一的哈希值。包括时间戳和客户端的IP等内容。如果你不使用https,你很容易受到火焰式攻击。

除此之外,您正在进行令牌生成和正确交换。

答案 1 :(得分:2)

发送时间(并将其包含在缓存中)确实是一种选择。

当您第一次请求会话令牌或会话密钥时,另一个选项是2阶段算法,然后将其用于会话,并将其TTL存储在服务器上(可以是允许的时间或请求数量) )

关于会话密钥的想法,请查看http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange

等方案

一次性令牌算法示例:

1)客户端组成对1次令牌的请求,使用密钥签署此请求并将其发送到服务器。

2)服务器生成密钥,使用相同的密钥对其进行签名并将其发送给客户端(连同签名)

3)客户端使用密钥验证令牌

4)客户端编写请求,包括令牌,并使用密钥签署整个请求正文,然后发送到服务器

5)服务器检查整体完整性和令牌有效性,然后发送响应(同样可以使用密钥签名进行完整性和作者身份验证)