【问题标题】:How do I generate a JWT to use in API authentication for Swift app如何生成 JWT 以用于 Swift 应用程序的 API 身份验证
【发布时间】:2022-01-31 19:59:48
【问题描述】:

我正在尝试使用 API 服务,该服务需要对其所有 API 调用进行 JWT 身份验证。

我了解 JWT 令牌是什么以及它们是如何使用的,我的问题是我正在编写一个 Swift 应用程序并且无法完全弄清楚生成令牌的过程,以便我可以将其作为 Bearer 附加到我的 API 调用。

  • 我可以在客户端(swift 应用)生成 JWT 令牌吗?
  • 创建一个 Google Cloud 函数以生成令牌,然后写回 Firebase 在我的 API 调用中使用?

【问题讨论】:

  • 这可能是一个误解。作为身份验证的一部分,身份验证提供程序可能会向您的应用返回 JWT。例如,在 OIDC 中,这是一个签名的 JWT,更准确地说,是包含用户信息的“id_token”。您的应用应“验证”此令牌,但应用通常不会创建此类 JWT。同样,如果您从任何令牌端点收到 access_token,这始终是一个不透明的值。在应用程序中,您永远不会尝试解析或验证访问令牌,即使此访问令牌实际上是您可以检查的 JWT(或 JWS)。
  • 我必须通过离开应用程序并让用户在浏览器上登录来通过 URL 将加密的用户名和密码发送到服务器?这方面的任何线索...

标签: swift jwt google-cloud-functions jwt-auth


【解决方案1】:

以下是使用 Apple 的 CryptoKit 在 Swift 中制作 JSON Web 令牌的方法。它使用https://jwt.io中的默认示例

import CryptoKit

extension Data {
    func urlSafeBase64EncodedString() -> String {
        return base64EncodedString()
            .replacingOccurrences(of: "+", with: "-")
            .replacingOccurrences(of: "/", with: "_")
            .replacingOccurrences(of: "=", with: "")
    }
}

struct Header: Encodable {
    let alg = "HS256"
    let typ = "JWT"
}

struct Payload: Encodable {
    let sub = "1234567890"
    let name = "John Doe"
    let iat = 1516239022
}

let secret = "your-256-bit-secret"
let privateKey = SymmetricKey(data: Data(secret.utf8))

let headerJSONData = try! JSONEncoder().encode(Header())
let headerBase64String = headerJSONData.urlSafeBase64EncodedString()

let payloadJSONData = try! JSONEncoder().encode(Payload())
let payloadBase64String = payloadJSONData.urlSafeBase64EncodedString()

let toSign = Data((headerBase64String + "." + payloadBase64String).utf8)

let signature = HMAC<SHA256>.authenticationCode(for: toSign, using: privateKey)
let signatureBase64String = Data(signature).urlSafeBase64EncodedString()

let token = [headerBase64String, payloadBase64String, signatureBase64String].joined(separator: ".")
print(token) // eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

【讨论】:

  • 这是一个很好的例子,如何使用 Apple 的新 CryptoKit 库创建签名的 JWT。但是,我们需要谨慎:您使用的是需要在各方之间共享的对称密钥。除非您有一种安全共享秘密的奇特方式,否则密钥可能最终位于应用程序的二进制文件中。移动应用程序被认为是“非机密”,这意味着任何人都可以拿到钥匙。这意味着:它不安全;)
  • @CouchDeveloper 如果您放弃通过 JWT 对网络请求进行身份验证,并且您的网络请求是机密的,那么您实际上是在增加攻击面。我会混淆我的二进制文件并使用 JWT。
  • 客户端上的访问令牌总是不透明的——也就是说,应用程序并不(不需要)知道它实际上是什么——因此,作为 JWT 的访问令牌基本上只是一堆八位字节。对于服务器发送给客户端的任何其他信息,情况并非如此:例如,在 OIDC 中,“id_token”将作为签名的 JWT 发送。在这种情况下,客户端需要使用密钥解析和验证 JWT。对于移动和 SPA,您应该使用使用公钥 - 私钥机制(RSA、eclyptic 曲线等)的算法。公钥可以安全地用于非机密客户端。
  • 因此,当您从服务器接收到被视为机密的数据(例如访问令牌)时,您应将其存储到密钥链中(这是非常安全的)。只要您使用 HTTPS 和正确的 TLS,您就可以信任服务器。因此,您从服务器获得的应该是您所追求的信息。您不能在应用程序的二进制文件中包含任何类型的机密数据,例如对称密钥。这只是是否值得破解应用程序,最终获得密钥的问题。 ;)
  • 如果攻击者能够读取您嵌入二进制文件中的密钥,他们同样能够破解您的 TLS 并读取您的应用从后端接收的密钥。一旦攻击者可以访问您的应用程序二进制文件,无论您有什么安全措施,无论是 JWT、混淆、TLS 等,它都结束了。显然这不是放弃 TLS 或 JWT 的理由(恰恰相反) .实际上,我认为混淆二进制文件是一个很好的折衷方案。到目前为止,还没有关于二进制混淆被破坏的报告。
【解决方案2】:

这取决于您计划如何签署您的令牌。从根本上说,您需要某种秘密来签署 JWT 的有效负载。

您的密钥是客户端已经拥有的 API 密钥吗?如果是这样,那么仅在客户端生成它并没有太大的危害。

您的秘密是超级机密的证书,您不能将其提供给客户吗?然后,您可能会想采用您的 Firebase 想法。

在这些情况下,让客户端通过 API 密钥进行签名是很常见的,但您一开始就锁定 API 的动机是这里的驱动力。

IBM-Swift 看起来是当今最完整的 JWT 库,如果您决定使用客户端的话。

Jsonwebtoken 是一个非常好的 JS,如果你决定部署一个 GC 函数。

这两个库都非常易于使用。

【讨论】:

  • 是的,secret 是无法发布的,所以看起来我需要走 GC 函数路线。您可以指出我的任何 GC 函数示例函数吗?,可以使用哪些触发器来工作?等等。
  • 尝试使用此处描述的 HTTP 函数:cloud.google.com/functions/docs/writing/http 您需要在此处通过环境变量注入您的秘密:cloud.google.com/functions/docs/env-var 您可以使用 Jsonwebtoken 文档中的示例对普通 JSON 对象进行签名,您将作为对发送到 Cloud Function(或通过 FireBase)的 HTTP 请求的响应返回:github.com/auth0/node-jsonwebtoken
  • 对于大多数用例,您不需要第三方库来编码 JWT。 Swift 的 CryptoKit 提供了你需要的所有功能。
  • @Eric 如果您需要支持 iOS 13 之前的 iOS 版本,那么 CryptoKit 不是一个选项?
  • @Gruntfluffle 不,CryptoKit 仅适用于 iOS 13 及更高版本。在早期的 iO​​S 上,您可以使用 CommonCrypto。看到这个:stackoverflow.com/a/52785143/1072846
猜你喜欢
  • 2019-06-30
  • 2015-01-08
  • 1970-01-01
  • 2019-10-30
  • 2019-08-11
  • 1970-01-01
  • 1970-01-01
  • 2018-09-11
  • 1970-01-01
相关资源
最近更新 更多