在安全的API通信中使用请求签名时,保护免受重放攻击


Protect from replay attacks when using request signatures in secure API communication?

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

谢谢!

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

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

发送时间(并将其包含到缓存中)实际上是一个选项。

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

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

一次代币算法示例:

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

2) 服务器生成密钥,用相同的密钥签名,并将其发送给客户端(与签名一起)

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

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

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