【问题标题】:Protect from replay attacks when using request signatures in secure API communication?在安全 API 通信中使用请求签名时防止重放攻击?
【发布时间】:2012-03-30 02:25:19
【问题描述】:

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

谢谢!

【问题讨论】:

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


    【解决方案1】:

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

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

    【讨论】:

    【解决方案2】:

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

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

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

    1-time token 算法示例:

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

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

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

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

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

    【讨论】:

    • 时间戳解决方案似乎真的很不确定。由于我的 API 框架和与之通信的库都是开源的,因此中间人可以构建一个侦听器,在有限的“时间戳”期限内侦听并发送完全相同的请求,从而获得身份验证令牌作为回报。如果可能的话,我想避免这种情况。
    • 查看使用 1-time 令牌的 2-phase api 的更新。您也可以使用 Diffie-Hellman 或类似的会话密钥方法完全加密通信
    • 如果你将事务包装在 TLS 中,也能完成同样的事情。
    • 是的,这是一种实用的方法,但@kristovaher 要求解释一下,所以我放了扩展版。此外,尽管它们可以使用 TLS,但许多公共 API 仍然使用令牌或 2 阶段身份验证
    • 好的,从这里得到了一些好主意。所以“最弱的请求”真的是最初的令牌生成吗?但是,如果发送的请求被窃取并“再次发送”,如何阻止重放攻击的发生呢?例如,如果它返回敏感信息?时间戳是唯一的选择吗? (所以我只需要在时间戳退休之前接受机会之窗吗?)
    猜你喜欢
    • 2016-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多