【问题标题】:PKE REST Auth using SHA-1 Hash使用 SHA-1 哈希的 PKE REST 身份验证
【发布时间】:2014-03-10 23:29:04
【问题描述】:

我正在设计我的第一个 RESTful API,并试图弄清楚我将如何对 API 调用进行身份验证。我过去曾与Gengo API (dev docs) 合作过,并且很幸运,因此不可否认,我的很多身份验证设计都基于该链接中描述的他们的算法。

总结他们的过程,创建一个有效/经过身份验证的 API 调用:

  1. 向他们注册一个帐户并生成一个公钥/私钥集。然后对于每个 API 调用:
  2. 获取正在进行调用的 UNIX 纪元时间戳。
  3. 根据您的私钥计算时间戳的 SHA-1 哈希值。
  4. 确保您的公钥、私钥和计算的哈希值(上图)在每个 API 调用中都以 3 个单独的 HTTP 参数的形式出现。

起初这让我有点困惑,但我能够使用他们的 API 快速进行身份验证。但我从来没有完全理解为什么我必须生成这个 SHA-1 哈希,而且我不知道他们在服务器端做了什么来实际验证我的 API 调用。

现在我正在编写自己的经过身份验证的 API,我需要了解这些内容。所以我问:

  1. 时间戳及其派生的 SHA-1 哈希有什么用途?为什么只要求用户在每次 API 调用时向我发送他们的公钥/私钥会不太安全?
  2. 这是pubkey + privkey + hashed_timestamp Gengo 使用标准化做法进行 API 身份验证的方法吗?如果是这样,它有名称/算法吗?还有其他同样安全的竞争对手吗?
  3. 我对整个 HMAC/SHA-1 的内容感到困惑(具体示例请参见上面的链接)。我一直认为 SHA-1 是一种单向函数,可以将字符串转换为类似于 MD5 提供的编码字符串。但在那个例子中(见链接),它看起来像是将 SHA-1 和字符串传递给一些 HMAC 算法。这个 HMAC 的用途是什么?为什么它需要 3 个参数(SHA-1、时间戳和私钥)?
  4. 最后,服务器端的 3 个参数(pub key、priv key、hashed timestamp)如何进行认证呢?如果我正在设计一个使用 pub/priv 键的系统,那么我会将它们视为用户名/密码组合,并检查数据库以查看该组合是否存在。但是散列的时间戳真的让我失望了。

【问题讨论】:

    标签: api rest authentication public-key-encryption hmac


    【解决方案1】:

    时间戳及其派生的 SHA-1 哈希有什么用途?为什么只要求用户在每次 API 调用时向我发送他们的公钥/私钥会不太安全?

    为了消除您似乎预先产生的任何误解,用户应该切勿通过网络发送私钥。私钥是为了保持私密。这是您和用户之间共享的秘密。重读 Gengo 链接,您会发现它仅用作 HMAC 函数的 参数。用户需要找到一种方法来保护它,但您的 API 不需要它来验证调用。

    时间戳有两个用途。首先,它是一段数据,您将获得其明文和 HMAC。您将使用用户的私钥重新计算您身边的 HMAC。如果 HMAC 检查,这意味着不仅时间戳没有被篡改,而且只有知道私钥的人才能发送它。它为那条数据提供了完整性和真实性。

    如果是简单的 SHA1,攻击者可以截获消息、更改时间戳并重新计算哈希。通过使用键控哈希,您可以确保发件人就是您认为的那个人。

    时间戳的第二个目的是防止重放攻击。即使使用密钥散列,攻击者也可能捕获旧请求并再次发送,可能会触发不需要的操作。如果您的用户对时间进行哈希处理,并且您对其进行测试并拒绝过时的请求,则可以防止此类重放攻击。

    这个 pubkey + privkey + hashed_timestamp 方法是 Gengo 使用 API auth 的标准化做法吗?如果是这样,它有名称/算法吗?还有其他同样安全的竞争对手吗?

    再一次,私钥不是通过管道发送的。使用 HMAC 进行 API 身份验证非常普遍。例如,它用于Amazon Web Services。以 Gengo 方式使用时,看似存在一对公钥/私钥的事实可能会令人困惑,它实际上仍然是对称密码学,并且私钥用作共享密钥。

    不过,我认为在经过 HMAC 处理的数据中不仅仅包含时间戳会更好。否则,攻击者可能会篡改请求的其他部分。标头、HTTP 动词和请求内容的哈希值也应包括在内。

    另一种方案是在客户端使用私钥签名(用私钥加密)一段数据,因此服务器只需要验证它使用客户端的公钥,不需要知道客户端的私钥。仍然需要嵌入时间信息以防止重播。我对这个方案了解不多,一开始可能很难可靠地将客户端与给定的公钥链接起来。

    这样做的目的是什么 HMAC 服务以及为什么它需要 3 个参数(SHA-1、时间戳 和私钥)?

    HMAC 是键控散列。考虑最简单的消息身份验证形式:hash(key + message)。发现这是不安全的(请参阅length extension attack),并且嵌套结构修复了该漏洞。

    HMAC 是该结构的通用名称:hash(k1 + hash(k2 + message)),其中k1k2 派生自实际密钥。因此,当我们执行 HMAC 时,我们需要传递将使用的实际哈希算法的名称(此处为 SHA-1)、消息(此处为时间戳)和密钥。

    最后,我如何处理 3 个参数(pub key、priv key、hashed 时间戳)在服务器端执行身份验证?如果我是 设计一个只使用 pub/priv 密钥的系统,然后我会 将它们视为用户名/密码组合并检查数据库 看看那个组合是否存在。但哈希时间戳是 真的把我丢在这里了。

    希望现在更清楚。您使用公钥作为标识符来检索私钥。您获取ts 标头并使用私钥重新计算它的HMAC。如果它与发送的 hmac 标头匹配,则该请求是真实的。您检查实际时间戳以查看它是否不是某个攻击者重放的旧请求。如果所有检查,呼叫可以通过。我认为最好在 HMAC 中嵌入所有重要信息,而不仅仅是时间戳。

    【讨论】:

      【解决方案2】:

      您需要任一公钥加密 HMAC,而不是两者。

      让我们稍后再回到时间戳,您将身份验证与完整性混淆了,我们稍后也会讨论。

      身份验证:在您的情况下,这是客户端向服务器证明知道某些秘密的地方。执行此操作的两种常见方法是通过公钥加密和使用 HMAC。

      • PKC:在使用服务之前会生成一个公钥/私钥对。客户端拥有私钥;服务器有公钥。重要提示:私钥永远不会离开客户端。特别是,服务器无权访问私钥。为了进行身份验证,客户端加密一些随机值 N(称为 nonce),并将 N 及其加密形式发送到服务器。服务器使用公钥解密加密的随机数并确认它等于提供的随机数。这向服务器证明了客户端拥有私钥。

      • HMAC:客户端和服务器事先同意共享密钥 K。为了进行身份验证,客户端创建一个随机数 N,计算 HMAC(K, N),并将 N 和 HMAC(K, N) 发送到服务器。服务器还计算 HMAC(K, N),因为它知道共享密钥并从客户端收到 N。如果计算和接收到的 HMAC(K, N) 值相同,则服务器知道客户端拥有共享密钥 K。

      与 PKC 相比,HMAC 方法有一个明显的弱点:如果服务器受到攻击,那么被攻击者会获得 K 的知识,然后可以使用它来伪装成客户端。

      如果使用 PKC,最好在客户端生成密钥对并将公钥发送到服务器。这样服务器永远不会拥有私钥。

      但是,除非通信通道是机密的(例如使用 SSL/TLS),否则这两种方法都有一个问题:重放攻击。被动观察者可以记录 N+加密形式,或 N+HMAC(K,N) 并将它们重播到服务器。然后服务器会认为观察者是一个有效的客户端。

      两种标准防御是:

      • 使用基于时间的随机数。

      • 服务器会记住以前见过的 nonce,并拒绝使用以前见过的 nonce 的新请求。

      这就是时间戳的来源,这里有更详细的讨论:Should I sign (with a public/private key) a form based authentication (no SSL)?

      完整性:我们已经向服务器证明我们是一个有效的客户端,但我们没有为请求本身提供任何保护。攻击者可以在飞行中修改我们的请求:我们会正确地进行身份验证,但随后会执行攻击者的请求,而不是客户端的原始请求。

      要解决这个问题,我们需要保护请求的完整性。我们可以使用与上述相同的机制来做到这一点。不仅仅是使用 nonce (N) 或 nonce+timestamp,而是将整个请求包含在已加密或散列的数据中。这里的一个重要考虑因素是加密和散列对字节进行操作,而不是 REST 请求。因此,您需要一种可靠的方法将 REST 请求(即 HTTP 方法、URL、请求参数)转换为字节。这通常被称为“规范化”:客户端和服务器都必须以完全相同的方式规范化请求,以便它们在给定请求的情况下加密/散列相同的字节。

      整个过程在诸如 OAuth 之类的东西中是标准化的,例如https://dev.twitter.com/docs/auth/authorizing-request

      回答您的具体问题:

      1. 时间戳防御重放攻击:被动观察者无法回复客户端的会话。 SHA-1 哈希用作 HMAC 的一个组件。

      2. 是的,说到点子上了。但我会使用它的成熟实现,而不是自己动手,比如基于 OAuth 的东西。

      3. HMAC 是一个带密钥的散列:它就像一个标准的加密散列(例如 SHA-1,除了您还在散列中包含一个共享密钥。只需将密钥连接到正在散列的数据就具有加密HMAC 构造避免的弱点。(https://en.wikipedia.org/wiki/HMAC.)

      4. 如果您使用的是 PKC,那么您在服务器上查找客户端的公钥(基于某些客户端 ID,它是 不是客户端的私钥),使用它来解密加密请求,并验证该请求是否与收到的请求匹配。如果您使用 HMAC,则查找客户端的共享密钥,规范化请求,计算 HMAC(K, R) 并验证它是否与收到的 HMAC(K, R) 匹配。在这两种情况下,您还必须验证时间戳/随机数以防止重放。

      但是:加密规则#1:不要自己动手。使用已建立的机制,例如 OAuth。您可能还想使用 SSL/TLS,这样您还可以使用客户端证书作为第三个身份验证选项。如果您使用这些,那么您还可以依靠 SSL/TLS 为您提供完整性和重放保护。但是,正确实施 SSL/TLS 证书验证似乎让许多开发人员感到困惑……

      【讨论】:

        猜你喜欢
        • 2015-12-20
        • 2020-07-06
        • 1970-01-01
        • 1970-01-01
        • 2019-05-07
        • 1970-01-01
        • 2016-05-30
        • 1970-01-01
        • 2016-06-06
        相关资源
        最近更新 更多