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

Php 在安全API通信中使用请求签名时防止重播攻击?,php,security,api,signature,man-in-the-middle,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-

我一直在阅读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是安全的,而不仅仅是市场营销

谢谢大家!

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

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

至于会话密钥的想法,请看下面的方案

1次令牌算法示例:

1) 客户端为1次令牌编写一个请求,使用密钥对该请求进行签名并将其发送到服务器

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

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

4) 客户端编写请求,包括令牌,并使用密钥对整个请求体进行签名,然后发送到服务器


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

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


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

时间戳解决方案似乎真的不确定。由于我的API框架和与之通信的库都是开源的,所以中间的人可以构建一个侦听器,侦听器在有限的时间戳周期内侦听并发送完全相同的请求,从而获得AuthTog的返回。如果可能的话,我希望避免这种情况。请参阅使用1次令牌的2阶段api的更新。此外,您还可以使用Diffie Hellman或类似的会话密钥方法对通信进行完全加密,如果您将事务包装在TLS中,则可以实现相同的目的。是的,这是一种实用的方法,但@kristovaher要求提供一些解释,因此我将扩展版本放在了后面。此外,尽管可以使用TLS,但许多公共API仍然使用令牌或2阶段AuthOk,从这里得到了一些好主意。那么“最弱的请求”实际上是初始令牌生成请求?但是,如果发送的请求被盗并“再次发送”,那么如何阻止重播攻击的发生呢?例如,如果它返回敏感信息?时间戳是唯一的选择吗?(所以我必须在时间戳失效之前接受机会之窗?)谢谢你的信任投票,我想我只是一个偏执的完美主义者。我可能会使用实际的HMAC来避免长度扩展攻击,尽管看起来你并不容易受到攻击,因为你把秘密放在最后而不是第一位。