如果仅能使用一次的随机数(Nonce)已经存在,OAuth中为什么需要时间戳?

42

一开始我误解了OAuth中的时间戳实现,认为超过当前时间30秒的时间戳将被拒绝,但最终证明这是错误的,原因包括我们无法保证每个系统时钟在分钟和秒方面足够同步,无论时区如何。后来我再次阅读来获得更清晰的理解:

“除非服务提供商另有规定,时间戳以自1970年1月1日00:00:00 GMT以来的秒数表示。时间戳值必须是正整数,并且必须等于或大于之前请求中使用的时间戳。”

来源:http://oauth.net/core/1.0/#nonce

这意味着时间戳仅与来自同一源的先前请求进行比较,而不是与我的服务器系统时钟进行比较。

然后我在这里阅读了更详细的描述:http://hueniverse.com/2008/10/beginners-guide-to-oauth-part-iii-security-architecture/

(快速阅读?- 跳到下面的粗体部分)

为了防止被篡改的请求再次被使用(重放攻击),OAuth使用nonce和时间戳。Nonce一词意味着“仅使用一次的数字”(number used once),它是一个独特且通常是随机的字符串,旨在唯一标识每个签名请求。通过为每个请求提供唯一标识符,服务提供商能够防止请求被多次使用。这意味着消费者为发送到服务提供商的每个请求生成一个唯一的字符串,并且服务提供商跟踪所有已使用的nonce以防止它们再次使用。由于nonce值包含在签名中,攻击者无法更改它而不知道共享密钥。

使用nonce可能会给服务提供商带来很高的成本,因为他们需要永久存储所有接收到的nonce值。为了使实现更容易,OAuth向每个请求添加了一个时间戳值,这允许服务提供商仅保留有限时间内的nonce值。当一个请求带有一个比保留时间范围早的时间戳时,该请求将被拒绝,因为服务提供商不再拥有那个时间段的nonce。可以安全地假设,在允许的时间限制之后发送的请求是重放攻击。OAuth提供了一种通用机制来实现时间戳,但是将实际实现留给了每个服务提供商(许多人认为这是规范应该重新审视的领域)。从安全角度来看,真正的nonce是时间戳值和nonce字符串的组合。只有在一起,它们才能提供一个永久独特的值,攻击者永远无法再次使用。

我感到困惑的原因是如果Nonce只被使用一次,为什么服务提供商会基于时间戳拒绝请求?"服务提供商不再拥有那个时间段的nonce"对我来说是令人困惑的,并且听起来好像只要在30秒内,一个nonce可以被重复使用,只要在最后一次使用的时间之内。

所以有人能为我澄清这个问题吗?如果nonce只使用一次,而且我没有将时间戳与自己的系统时钟进行比较(因为这显然是不可靠的),那么时间戳的意义是什么?时间戳只相对于彼此,这似乎与唯一的nonce要求无关。

5个回答

38

时间戳用于允许服务器优化其存储的nonce。基本上,将读取nonce视为时间戳和随机字符串的组合。但是通过具有单独的时间戳组件,服务器可以使用短窗口(例如15分钟)实现基于时间的限制,并限制其所需存储量。如果没有时间戳,服务器将需要无限存储空间来保存曾经使用过的每个nonce。

假设您决定允许时钟与客户端之间的最多15分钟时间差,并在数据库表中跟踪nonce值。表的唯一键将是“客户端标识符”、“访问令牌”、“nonce”和“时间戳”的组合。当新请求进入时,请检查时间戳是否在您的时钟内的15分钟范围内,然后在表中查找该组合。如果找到了,则拒绝调用,否则将其添加到表中并返回所请求的资源。每次向表中添加新的nonce时,删除任何时间戳早于15分钟的“客户端标识符”和“访问令牌”组合的记录。


那么我每6小时清除一次Nonce表,始终确保一个Nonce只使用一次,并且传入的时间戳大于或等于曾经使用的最后一个成功请求的时间戳。这样,如果他们尝试重新使用Nonce,它将失败,但是如果他们等待6个小时并尝试使用该请求,它仍将失败,因为时间戳将比上次请求更早。然而,如果请求从未通过,则可以再次使用...所以我不知道这如何防止重放攻击。 - MetaGuru
4
你需要保持一个滚动队列,而不是每6小时清空它。你要为每个客户端标识符维护一个nonce值的列表,并在队列中的时间戳大于窗口期限(比如15分钟)时清除该值。如果一个请求的时间戳早于你的窗口期限,你将直接拒绝它;否则,你将在队列中查找时间戳+nonce值,如果没有找到就提供受保护的资源。 - Eran Hammer
我在想我应该把这个队列存储在哪里,或者它是否只是内置于我用于从nonce表中检索的查询中?你说的每个客户标识符是什么意思?我目前将Nonce与AccountID一起存储,但是如何区分“在队列中”的Nonce和仅在表中的Nonce? - MetaGuru
谢谢,但是我不能将它与我的系统时钟进行比较,对吧?如果服务器没有同步,那么就会出现错误的失败。我只应该将传入的时间戳与先前请求的时间戳进行比较? - MetaGuru
1
你需要将其与时间戳进行比较,并允许高达15分钟的时钟偏差。如果客户端的时钟超过15分钟(当然是GMT),则应返回一个错误,告诉客户端进行同步。如果你的开发人员编写桌面或基于浏览器的应用程序,则应为应用程序时间戳需求使用时间服务而不是本地时钟。此外,如果您不需要重放保护,则可以完全忽略nonce。今天,Twitter检查nonce,而Yahoo和Google则不检查。 - Eran Hammer
2
如果我们坚持要求每个用户的后续时间戳必须大于前一个时间戳,那么我们还需要一个随机数吗? @eran-hammer - tofutim

9

好的,经过足够的思考,我相信我已经解决了这个问题。

他们希望我始终知道上一个成功请求的时间戳,因此如果任何时间戳早于该时间戳,则将被忽略。

此外,随机数必须是唯一的,但我只会存储它们到某个日期范围内,因此如果时间戳太旧,随机数将被删除,然后可以再次使用,但因为最后使用的时间戳也被存储,即使随机数被认为是唯一的,也不能重新使用旧的请求,因为那个请求的时间戳已过时。

然而,这仅适用于签名。如果他们更改请求的时间戳或随机数,则签名将不再与请求匹配,并且将被拒绝(因为时间戳和随机数都是签名创建的一部分,他们没有签名密钥)。

哇!


0
如果 OAuth 仅使用时间戳,攻击者可以相对容易地猜测下一个时间戳,并将其自己的请求注入到过程中。他们只需要执行“前一个时间戳 +1”。
通过使用以加密安全方式生成的 nonce(希望如此),攻击者无法简单地注入 TS+1,因为他们没有适当的 nonce 来验证自己。
将其视为需要同时使用门禁卡和 PIN 码的安全门锁。你可以窃取门禁卡,但仍无法进入房间,因为你不知道 PIN 码。

1
你错过了问题。我理解nonce,但如果nonce只能使用一次,我不认为时间戳有什么附加价值。 - MetaGuru
可能有一个数据包丢失了。可能会有多个nonce同时“在飞行”中。时间戳的存在是为了保证事物的顺序。 - Marc B
一旦使用了一次性密码,就不能再次使用它们,而且它们是独一无二的。 - MetaGuru

0

暂时无法评论,所以作为答案发布。回复@tofutim的评论

为什么要使用nonce?

确实,如果我们坚持认为新请求的时间戳值必须大于所有先前请求的时间戳,那么nonce似乎没有什么意义:

  • 重放攻击被防止了,因为提供者会拒绝具有与上一个相同时间戳的消息

  • 是的,对于攻击者来说,下一个时间戳很容易猜测 - 只需使用timestamp + 1 - 但攻击者仍然无法篡改时间戳参数,因为所有参数都使用消费者的密钥(和令牌密钥)进行签名

然而,阅读OAuth 1.0a规范揭示了以下内容:

除非服务提供商另有规定,否则时间戳表示自1970年1月1日00:00:00 GMT以来的秒数。时间戳值必须是正整数,并且必须等于或大于之前请求中使用的时间戳。
然后,消费者应生成一个对于该时间戳的所有请求都是唯一的Nonce值。
因此,在您发送具有相同时间戳的多个请求时,会使用nonce来防止重放攻击。
为什么允许发送具有相同时间戳的请求?
考虑这样一种情况:您想并行地向独立资源发送多个请求,以更快地完成处理。从概念上讲,服务器逐个处理每个请求。由于依赖于诸如操作系统、网络数据包传输、服务器逻辑等众多因素,您无法知道请求的到达顺序。
如果您发送具有增加时间戳的请求,仍然有可能优先处理高时间戳的请求,然后所有低时间戳的请求都将失败。相反,您可以发送具有相等时间戳但不同nonce的请求。

-1

可以合理地假设有人会尝试使用暴力破解来破解随机数。时间戳可以降低某人成功的可能性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接