【问题标题】:HTTP Request signature without session没有会话的 HTTP 请求签名
【发布时间】:2011-05-29 15:20:16
【问题描述】:

我正在考虑一个休息网络服务,以确保发送给他的每个请求:

  • 请求是由声明它的用户生成的;
  • 请求未被其他人修改(uri/method/content/date);
  • 对于 GET 请求,应该可以生成一个包含足够信息的 URI,以检查签名并设置到期日期。这样一来,用户就可以在有限的时间内将临时 READ 权限委托给协作者,使用生成的 URI 访问资源。

客户端通过 id 和基于其密码的内容签名进行身份验证。

根本不应该有会话,所以服务器状态!服务器和客户端共享一个密钥(密码)

经过思考并与一些非常好的人交谈后,似乎没有其他服务可以像我的用例那样简单地做到这一点。 (HTTP Digest 和 OAuth 可以通过服务器状态来做到这一点,而且非常健谈)

所以我想象了一个,我正在向您的伟大的 cmets 询问它应该如何设计(我将发布它开源并希望它可以帮助其他人)。

该服务使用自定义“内容签名”标头来存储凭据。经过身份验证的请求应包含此标头:

Content-signature: <METHOD>-<USERID>-<SIGNATURE>

<METHOD> is the sign method used, in our case SRAS.
<USERID> stands for the user ID mentioned earlier.
<SIGNATURE> = SHA2(SHA2(<PASSWORD>):SHA2(<REQUEST_HASH>));
<REQUEST_HASH> = <HTTP_METHOD>\n
                 <HTTP_URI>\n
                 <REQUEST_DATE>\n
                 <BODY_CONTENT>;

请求在创建 10 分钟后失效。

例如,典型的 HTTP 请求是:

POST /ressource HTTP/1.1
Host: www.elphia.fr
Date: Sun, 06 Nov 1994 08:49:37 GMT
Content-signature: SRAS-62ABCD651FD52614BC42FD-760FA9826BC654BC42FD

{ test: "yes" }

服务器会回答:

401 Unauthorized

200 OK

变量是:

<USERID> = 62ABCD651FD52614BC42FD
<REQUEST_HASH> = POST\n
                 /ressource\n
                 Sun, 06 Nov 1994 08:49:37 GMT\n
                 { test: "yes" }\n

URI 参数

一些参数可以添加到 URI 中(它们会重载标头信息):

  • _sras.content-signature=-- :将凭据放在 URI 中,而不是 HTTP 标头中。这允许用户共享已签名的请求;
  • _sras.date=Sun, 06 Nov 1994 08:49:37 GMT(请求日期*):创建请求的日期。
  • _sras.expires=Sun, 06 Nov 1994 08:49:37 GMT(过期日期*):告诉服务器请求不应在指定日期之前过期

*日期格式:http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.18

感谢您的 cmets。

【问题讨论】:

    标签: web-services http rest restful-authentication stateless-session


    【解决方案1】:

    在设计签名协议时需要考虑几个问题。其中一些问题可能不适用于您的特定服务:

    1- 通常在非标准标头中添加“X-Namespace-”前缀,在您的情况下,您可以将标头命名为:“X-SRAS-Content-Signature”。

    2- Date 标头可能无法为 nonce 值提供足够的分辨率,因此我建议时间戳至少具有 1 毫秒的分辨率。

    3- 如果您至少不存储最后一个 nonce,仍然可以在 10 分钟窗口内重播消息,这在 POST 请求中可能是不可接受的(可能在您的 REST Web 服务中创建具有相同值的多个实例) .这对于 GET PUT 或 DELETE 动词来说应该不是问题。

    但是,在 PUT 上,这可以通过在建议的 10 分钟窗口内强制更新同一对象多次来用于拒绝服务攻击。在 GET 或 DELETE 上存在类似问题。

    因此,您可能需要至少存储与每个用户 ID 关联的最后使用的 nonce,并在所有身份验证服务器之间实时共享此状态。

    4- 此方法还要求客户端和服务器时钟同步,偏差小于 10 分钟。如果您有不控制时钟的 AJAX 客户端,这可能很难调试,或者无法强制执行。这也需要在 UTC 中设置所有时间戳。

    另一种方法是放弃 10 分钟窗口要求,但验证时间戳是否单调增加,这再次需要存储最后一个 nonce。如果客户端的时钟更新到上次使用的 nonce 之前的日期,这仍然是一个问题。访问将被拒绝,直到客户端的时钟经过最后一个 nonce 或服务器 nonce 状态被重置。

    对于无法存储状态的客户端,单调递增计数器不是一个选项,除非客户端可以向服务器请求最后使用的 nonce。这将在每个会话开始时完成一次,然后计数器将在每次请求时递增。

    5- 您还需要注意由于网络错误导致的重传。您不能假设在 TCP 连接断开之前,服务器尚未收到客户端尚未收到 TCP Ack 的最后一条消息。因此,需要在 TCP 级别以上的每次重传和使用新的 nonce 重新计算签名之间增加 nonce。但是需要添加消息编号以防止在服务器上重复执行:双 POST 将导致创建 2 个对象。

    6- 您还需要对用户 ID 进行签名,否则,攻击者可能会为所有未达到重播消息的 nonce 的用户重播相同的消息。

    7- 你的方法不能保证客户端服务器是真实的并且没有被 DNS 劫持。服务器身份验证通常被认为对安全通信很重要。可以通过使用与请求相同的随机数对来自服务器的响应进行签名来提供此服务。

    【讨论】:

    • 嗨@jean。 1- 我会检查 RFC。 2-我不明白你的意思,没有随机数,但让我们看看下一个问题。 3-是的,你是对的。为了正确处理重放攻击,我应该将使用过的签名存储到 memcached 服务器中,以查看它是否已被使用(10 分钟后过期)。 4-我可以同步它们,首先请求给服务器日期,ajax客户端检查服务器和他之间的差异。并提供一个好的 UTC DATE。 5-那不是铅。并且可以检查签名是否已被使用 6- 是的,对! 7- 是的,我会检查以添加对它的支持。
    • @Sébastien, 2- 日期实际上在您提议的协议中用作随机数。如果在同一秒内发出两个请求,它们将具有相同的日期,并且应该因为使用了与前一个请求相同的随机数而被拒绝。将分辨率提高到一毫秒可能就足够了,也可能不够。 4- 如果您使用设置请求进行同步,则使用计数器可能更容易。此外,您可能仍有背景日期更新问题。 5- 如果您检查签名,您应该拒绝第二条消息为未经授权(重播),这可能会使客户感到困惑。
    • 2- 如果已经看到日期,我不会拒绝请求。也许我以前不清楚某个地方。 4-我只存储本地时间和服务器时间之间的秒差。这可以通过从服务器发送的任何请求来完成。无需为此提出请求,只需检查最后一个。 5- 这是预期的行为。如果请求似乎失败了,用户必须使用新签名创建一个新请求(以及日期更改的秒部分)。
    • @Sebastien 2-如果没有拒绝已经看到的日期,则确实没有随机数。这会受到重放攻击,例如多个 POST 导致创建 2 个或更多对象。在这种情况下,我不明白日期的目的。您需要澄清您想要完成的任务:“这样,用户可以在有限的时间内将临时 READ 权限委托给协作者,使用生成的 URI 对资源进行访问”。这听起来像是一个安全问题,因为委派应该在授权级别而不是消息完整性级别处理。 5- 这可能导致双重 POST。
    • 2- 随机数是哈希签名。一个请求不能被使用两次。如果请求改变,签名改变。在请求没有到达服务器的情况下,我制作一个新的相同但带有新签名的新签名(日期用于签名)。代表的意思是我想给某人一个 URI 来访问我有权访问的资源。我可能会考虑,因为你是真的,那不是做这件事的正确地方。 5-我需要在其他地方处理。在 REST 架构中,我必须尽可能地做到 IDEMPOTENT。
    【解决方案2】:

    我会注意到您可以使用 OAuth 完成此操作,最值得注意的是客户端和服务器共享秘密的“2-legged OAuth”。见https://www.rfc-editor.org/rfc/rfc5849#page-14。在您的情况下,您想省略 oauth_token 参数并可能使用 HMAC-SHA1 签名方法。这没有什么特别好说的。您无需通过 OAuth 令牌获取流程来执行此操作。这样做的好处是可以使用多个现有的开源 OAuth 库中的任何一个。

    就服务器端状态而言,您确实需要跟踪哪些秘密与哪些客户端相关,以及最近使用了哪些随机数(以防止重放攻击)。如果您通过 HTTPS 运行,您可以跳过随机数检查/生命周期,但如果您打算这样做,那么 HTTPS + Basic Auth 可以为您提供您所描述的一切,而无需编写新软件。

    【讨论】:

    • 谢谢。我不确定我是否真的想进入 OAuth 大机器。但也许我会尝试“2-legged OAuth”。谢谢你的回答。
    猜你喜欢
    • 2011-08-19
    • 1970-01-01
    • 1970-01-01
    • 2012-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-16
    相关资源
    最近更新 更多