Получение JWKS для Firebase в формате rfc7517

Я использую Firebase для аутентификации пользователей в своем приложении. Firebase генерирует токен JWT, который мне нужен для аутентификации на моем сервере. Я использую tyk.io для этого. Tyk поддерживает эти токены, но требует, чтобы источник данных для открытых ключей был в формате https://www.rfc-editor.org/rfc/rfc7517.

Есть ли простой способ получить это прямо из Google/Firebase?

Я знаю, что могу получить ключи от https://www.googleapis.com/service_accounts/v1/metadata/x509/[email protected], но это не ожидаемый формат.

Я также могу получить jwk из https://www.googleapis.com/service_accounts/v1/jwk/[email protected], который является правильным форматом, но не содержит ключей (мне нужны ключи в поле X5c, поэтому цепочка сертификатов X.509)

Неправильно говорить, что «это правильный формат, но не содержит ключей»: параметры «n» и «e» являются открытым ключом (модуль и открытый показатель). Поле «x5c» — это сертификат, содержащий ключ, но Firebase не использует и не нуждается в использовании сертификата X.509 для инкапсуляции и публикации ключа, поскольку публикация открытого ключа RSA выполняется с помощью службы SSL/TLS с использованием сертификат, подписанный действительным ЦС. Таким образом, получение JWK от googleapis.com... — это способ безопасно передать вам ключ. Поэтому нет необходимости иметь сертификат, и Google его не предоставляет.

Alexandre Fenyo 09.04.2019 18:14

Спасибо за ваш комментарий. Возможно, мой вопрос был недостаточно точным. Мне нужно поле x5c в jwks, которое я получаю от Google/firebase. К сожалению, это единственный формат, который Tyk может обрабатывать. Я просто хочу знать, легко ли это возможно или нет?

Pierre Leonard 09.04.2019 19:48

В документации Tyk предлагается только два способа проверки подписи токена: открытый ключ RSA и HMAC с использованием общего секрета, в них не говорится о сертификате: поле было бы необходимо?

Alexandre Fenyo 09.04.2019 23:32

Интересная часть находится по адресу tyk.io/docs/security/your-apis/json-web-tokens/…. Кроме того, вы можете проверить соответствующий код шлюза Tyk по адресу github.com/TykTechnologies/tyk/blob/….

Pierre Leonard 10.04.2019 08:01

Спасибо, что указали мне на googleapis.com/service_accounts/v1/jwk/…, я не смог найти его нигде в документации Google.

darnmason 02.09.2020 07:21
Интеграция Angular - Firebase Analytics
Интеграция Angular - Firebase Analytics
Узнайте, как настроить Firebase Analytics и отслеживать поведение пользователей в вашем приложении Angular.
6
5
2 601
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как вы заметили, читая Библиотека Tyk на GitHub, Tyk решил поддерживать только ключи RSA, опубликованные в сертификате, в наборах JWK.

ПРЕДВАРИТЕЛЬНЫЕ ПРИМЕЧАНИЯ:

Ключ RSA, который Google использует для подписи веб-токена JSON, берется из одного из двух ключей, опубликованных по адресу https://www.googleapis.com/service_accounts/v1/jwk/[email protected].

Эти два ключа те, которые используются для создания двух сертификатов по адресу https://www.googleapis.com/service_accounts/v1/metadata/x509/[email protected]

Обратите внимание, что эти сертификаты являются самоподписанными, вот содержимое одного из них:

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 4804715264884888226 (0x42adc713b25c52a2)
    Signature Algorithm: sha1WithRSAEncryption
        Issuer: CN=securetoken.system.gserviceaccount.com
        Validity
            Not Before: Apr  2 21:20:50 2019 GMT
            Not After : Apr 19 09:35:50 2019 GMT
        Subject: CN=securetoken.system.gserviceaccount.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:cc:7c:14:e6:5c:95:94:4b:95:74:0d:47:9d:e1:
                    [...]
                    60:d1
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Key Usage: critical
                Digital Signature
            X509v3 Extended Key Usage: critical
                TLS Web Client Authentication
    Signature Algorithm: sha1WithRSAEncryption
    [...]

Как видите, эмитент имеет то же значение, что и субъект, поэтому цепочка сертификатов состоит из одного самозаверяющего сертификата. Это означает, что вы не можете проверить действительность этого сертификата с помощью центра сертификации: нет глобального известного центра сертификации, который подписал бы открытые ключи RSA от Google для создания этих сертификатов. Но сертификаты загружаются с помощью SSL/TLS с веб-сервера Google, который аутентифицируется с помощью сертификата, подписанного GlobalSign, поэтому загрузки сертификатов с использованием SSL/TLS достаточно, чтобы убедиться, что эти сертификаты содержат ключи RSA, которые использует Google. подписать JWT.

Сертификаты действительны только в течение нескольких недель и имеют перекрывающийся период проверки, чтобы избежать перекоса часов, а также существует механизм с изменяющимся ключом, который применяется почти каждые две недели.

ОТВЕТ НА ВАШ ВОПРОС:

Вам необходимо самостоятельно создать источник открытого ключа, чтобы Google мог работать с Tyk: вы должны создать на своем сервере приложений документ, содержащий набор JWK. Мы предполагаем, что вы публикуете этот набор JWK здесь: https://my-application-server.com/jwks.json.

Итак, в вашем определении API Tyk в секретном поле JWT вам нужно указать этот URL-адрес набора JWK: https://my-application-server.com/jwks.json.

Для этого см. часть о Секретное поле JWT на этой странице: https://community.tyk.io/t/multiple-auth-schemes-for-single-api-definition/694/4

Вам нужно обновлять этот документ каждую неделю, потому что Google обновляет ключи примерно каждые две недели.

Этот документ можно создать с помощью следующей команды оболочки, используя только curl и процессор командной строки JSON с именем jq:

curl -s 'https://www.googleapis.com/service_accounts/v1/metadata/x509/[email protected]' | jq '[ to_entries | .[] | {alg: "RS256", kty: "RSA", use: "sig", kid: .key, x5c: (.value | sub(".*"; "") | sub("\n"; ""; "g") | sub("-.*"; "")) } ] | {"keys": .}'

Вот вывод этой командной строки:

% curl -s 'https://www.googleapis.com/service_accounts/v1/metadata/x509/[email protected]' | jq '[ to_entries | .[] | {alg: "RS256", kty: "RSA", use: "sig", kid: .key, x5c: (.value | sub(".*"; "") | sub("\n"; ""; "g") | sub("-.*"; "")) } ] | {"keys": .}'
{
  "keys": [
    {
      "alg": "RS256",
      "kty": "RSA",
      "use": "sig",
      "kid": "7d2f9f3fb83d6337497b6f7cd2cff4dfa5c2e8b8",
      "x5c": "MIIDHDCCAgSgAwIBAgIIQq3HE7JcUqIwDQYJKoZIhvcNAQEFBQAwMTEvMC0GA1UEAxMmc2VjdXJldG9rZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wHhcNMTkwNDAyMjEyMDUwWhcNMTkwNDE5MDkzNTUwWjAxMS8wLQYDVQQDEyZzZWN1cmV0b2tlbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMx8FOZclZRLlXQNR53h+mYYjo9X4Hi38dAsLrP2iRzt8PowOnqx7hxpr9Ag7NKTSAOXTUAmObCRkEooRLe6jcScu+nttpjqqvtOyzhTl2szbdsiRhveXmOwMMbZ/DCkXll6i2NoeeRxVy4qxMDMPM6pokjsUyuq9wkWH+fiUG8rYSZVhpCqfOtqoTBu0zf+PyuGDPlLKKkE6Y7WKp5Go/tIMS6kTz5vhnA3M0HNWdZDy+06kT0eTxajzcs/QXiqmMzJEsJ7ln0Qh1KnOZwMH578y9GYM3ytMdiybDQM0c4cWtLp0REjlKyzqh0LLA7fmdjmEmIgOSy1wzftcKnfYNECAwEAAaM4MDYwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADggEBAFpLrULiau0nFLjRXxt9lwjgft1elBt265Hu88TU3132Wbh00Yvm7hlOA34gVIVNPcgT5lCxc4qVLXbA6yPtnyDubvULmVxyCSKfX/2M4Td+yPF99xR3VVCpATPAVjtOo819Q/Of+icQlmSoy/I0lFJewwrqcRc0eC9UgzF+EvGXHzIfoNlQgFjf/fnG1OV7d2Zr8bj+Jk/zZwVRstKCTrPgyqCYe/y7PU9q0aIQnMRvYKdLj/TfaBolQ12Tlb2j+nGMrPH5uVsUUu6nZluhaMvmlhp8glvslmjlXCIuce/N8FSw7zVf/ofRrDzTw98N1DZG2aLRyRYdmsXDBqMaac8 = "
    },
    {
      "alg": "RS256",
      "kty": "RSA",
      "use": "sig",
      "kid": "ff1df5a15b5cf582b61a21385c0cfaedfdb6a748",
      "x5c": "MIIDHDCCAgSgAwIBAgIIcqcNMyhOv18wDQYJKoZIhvcNAQEFBQAwMTEvMC0GA1UEAxMmc2VjdXJldG9rZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wHhcNMTkwMzI1MjEyMDUwWhcNMTkwNDExMDkzNTUwWjAxMS8wLQYDVQQDEyZzZWN1cmV0b2tlbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKnDRgOsHY55P2i7wX6Uh8YO/rBWmGgVgeBqCowbHopF5HA1EdF0NXSmBn1Myg+DLFqxf0nvsi8B5pjd/rNtVPX6OUIkAKGPyva/d2aQqsHliCFh81QDs2vHIeIAThbQZP514t/z2M79SWR7A0vRYcWf+I+eTL6Vf1nqO3cFwTJVtwiTPom+NjZKx7ukowtqm1mVef+FqceC5zx8D5wzLLtUx/tMPvnXaysSjNN+86cPKc02kumCqlt7Yuf5G9VptjAVqsQyL/X5WuIVuzkFrfh/IPidw7Wzm3s5u928aLNSNbFpEpeXqJ8utD4AZnfm9mg6PYNtFWIB/L6xf21iZOECAwEAAaM4MDYwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQEFBQADggEBAEdXAGI27mRT+Qkz9vbGlGbKJZKLG6b6c/SAQkOZJDOX4sJ16WgbfsixGBEWmvMMiEwhWV0hbhTiEC22xUd7cRP6veRlKba4rKoYA0x3GJhpDpAviuKPFkCanLFlFOXouexQIxBudWm32B8YFpLW9ds8m9yFmQZwE5GZs1hJ1jb2z2u7AuZNdQnaQ7mKy7Vmt3yHb9NjPlvmQ//ijFR3Lw4XB3nlYcL77mjjd3fhBodfUFkPJpsY2wOQpRLxDbvjHsXSfsgQ+/a+9IjKj0F2YOu9HnvjTXCopWObA9AGV6HR2L6RGaRLTwH+xV2El8UrzTYFPPN/URLui3XtaGdiREg = "
    }
  ]
}

Содержимое этого вывода должно быть сохранено в файле, соответствующем https://my-application-server.com/jwks.json.

Большое спасибо за точный ответ и все дополнительные подробности!

Pierre Leonard 11.04.2019 09:57

На самом деле для использования с Tyk команда должна быть: curl -s 'https://www.googleapis.com/service_accounts/v1/metadata/x50‌​9/securetoken@system‌​.gserviceaccount.com‌​' | jq '[ to_entries | .[] | {alg: "RS256", kty: "RSA", use: "sig", kid: .key, x5c: [(.value | @base64) ] } ] | {"keys": .}'

Pierre Leonard 07.05.2019 13:41

Другие вопросы по теме

Проблема с созданием открытого ключа RSA из текста в Bouncy Castle
Как узнать, когда связаться с конечной точкой токена обновления?
Когда я делаю запрос POST на golang api с помощью POSTMAN, я успешно получаю токен jwt в виде файла cookie, но когда я делаю это из браузера, я не получаю файл cookie
Я использую стратегию аутентификации паспорт-jwt в своем приложении nestJS (с authGuard), как получить доступ к полезной нагрузке токена в моем контроллере?
Аутентификация на основе ролей на конечных точках Restful в Java
Io.jsonwebtoken.security.weakkeyexception: размер ключа проверки составляет 48 бит, что недостаточно безопасно для алгоритма HS256
Django Rest с JWT, получение AttributeError: недопустимая настройка API: «JWT_PAYLOAD_HANDLER»
Как переопределить сообщение формата DefaultHTTPErrorHandler
Как я могу вычислить подпись OAuth для учетной записи службы?
Метод Spring Security getprincipal() возвращает строку (имя пользователя) вместо класса UserDetails