2013-05-14 30 views
1

我正在从一个应用程序到另一个应用程序进行API调用。我处理授权通过传递md5版共享的秘密+时间戳...如何通过可靠的时间戳传递API令牌

$token = md5($secret . time()); 

然后在API端点,我检查这样的请求的真实性...

if (md5($shared_secret . time()) == $token) 
    ...do stuff 

这工作。但它不如我想要的那么可靠。我怀疑这是由于网络延迟(或者我的速度慢的本地主机服务器)导致时间戳一秒钟左右不匹配。

我通过删除时间戳的最后一位数字,以一种懒惰的方式解决了这个问题,从而为我的缓存服务器创建了长达10秒的窗口来进行呼叫。不过,我对此并不满意,因为如果这次电话会在第9秒的末尾落下,我会再次遇到相同的问题(发送####### 49!=在##处收到###### 50)。

必须有更好的方法来做到这一点。它是什么?

回答

2

考虑使用token = time || MAC(time, shared_secret)其中||是串联的,MAC是消息认证算法,如HMAC,它采用一个密钥和一些数据并产生一个认证标签。在服务器端,检查MAC是否有效,并且时间(以纯文本接收)在可接受的窗口内。

这比您当前的解决方案更安全(md5使可怜的MAC),并且还解决了您的窗口问题。

请注意,该方案容易在您允许的错误窗口内进行重播攻击(例如,同一令牌可能在一秒内发送十次,而服务器无法识别)。

+0

你是完全正确的。我忘了发送纯文本的时间戳!这正是我过去做过的事情,我只是简单地忘记了。我很想知道更多关于你对MAC和md5的看法。为什么MD5是一个糟糕的选择? (顺便说一下,我使用PHP) – emersonthis

+0

[扩展长度攻击](https://en.wikipedia.org/wiki/Length_extension_attack)是这个问题的构造问题。例如,根据时间格式和/或接收者解释时间的灵活程度,攻击者可能能够使用令牌在未来创建新的令牌,并通过接收者的验证。 PHP有一个[HMAC实现](http://php.net/manual/en/function.hash-hmac.php)。 HMAC在与md5一起使用时被认为是安全的,但除非你有特别的理由使用md5,否则我建议sha256。 – Michael

+0

PHP HMAC非常值得了解。但是,我不是100%确定如何将其应用于我的情况,因为我没有发送任何加密数据。只是共享的秘密+时间戳。那么这个'hmac('md5','foobar',$ secret)是一个比简单的'md5($ secret)'更好的标志吗?或者也许它们是等价的,'hmac'的优点是可以使用sha256吗? – emersonthis

0

改为使用随机数?将该随机数保存到数据库或某个永久性存储器,以确保不使用同一个存储器。

与你的'第九个第二个问题'相反,你有类似的问题几秒钟### ... 0到### ... 9当你截断尾部0到9时散列到相同的值。将允许在10秒的时间内重放。

看起来像这将是更多的保证/检查真实性的问题。

您必须将明文和散列文本一起发送给服务器进行检查,但这似乎比时间戳方法好一点。

无论哪种方式,只用这两个参数,你只是检查它不是一个重复的请求,而不是验证任何东西。

+0

我不确定你提出的解决方案。但是,您似乎可能误解了某些内容:时间戳不适用于身份验证。它被用来保护共享的秘密。没有它,呼叫很容易被拦截,而令牌也会受到影响。通过时间戳,可以截获API调用,但该令牌在1(0)秒后无用。合理? – emersonthis

+0

我想我着迷于此:“我检查这样的请求的真实性” – asafreedman

+0

我的评论是否阐明了为什么我包含时间戳? – emersonthis

0

使用时间戳不是正确的方法,因为时间在系统间不可靠。也许你可以使用消息的长度/散列作为参数。不幸的是,它不会阻止攻击者的回放。

纠正我,如果我错了,但好像你正在处理身份验证(即发件人是他们说他们是谁)而不是授权。我建议你使用SSL/TLS来确保传输的安全,以了解传输是否被代理。

+0

如果时间戳不是正确的方式,那么*是正确的方式?我意识到SSL会加密整个呼叫,但这不是我问的问题的答案。由于这里不重要的原因,我的系统不能依赖于SSL。 – emersonthis

+0

对不起,编辑我的文章 - 通常认为时间戳是好的,因为它是不可靠的。 – badunk