Zum Inhalt

jwt-verification: JWT-Verifizierungsbibliothek für nginx-module-lua mit JWKS-Integration

Installation

Wenn Sie noch kein RPM-Repository-Abonnement eingerichtet haben, melden Sie sich an. Dann können Sie mit den folgenden Schritten fortfahren.

CentOS/RHEL 7 oder Amazon Linux 2

yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-jwt-verification

CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023

dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-jwt-verification

Um diese Lua-Bibliothek mit NGINX zu verwenden, stellen Sie sicher, dass nginx-module-lua installiert ist.

Dieses Dokument beschreibt lua-resty-jwt-verification v0.7.0, das am 30. Oktober 2025 veröffentlicht wurde.


JWT-Verifizierungsbibliothek für OpenResty.

OPM LuaRocks Tests

Beschreibung

JWT-Verifizierungsbibliothek für OpenResty.

Ziel des Projekts ist es, ein modernes und schlankeres Ersatz für lua-resty-jwt mit integrierter Unterstützung für JWKS zu sein.

Dieses Projekt bietet keine Funktionen zur Manipulation oder Erstellung von JWTs: Sie können nur Tokens verifizieren/entschlüsseln.

Nicht-Ziele der Bibliothek

  • JWT-Erstellung/Änderung
  • Vollständige Funktionalität im Sinne der Vollständigkeit der RFCs.
  • Sinnlose und unsichere RFC-Funktionen (z. B. alg none) werden nicht implementiert.

Unterschiede zu lua-resty-jwt

Die Hauptunterschiede sind: - Keine JWT-Manipulation jeglicher Art (Sie können sie nur entschlüsseln/verifizieren) - Einfachere interne Struktur, die auf neueren lua-resty-openssl und OpenSSL-Versionen basiert. - Unterstützt verschiedene JWE-Algorithmen (siehe Tabellen oben). - Automatische JWT-Verifizierung bei gegebenem JWKS-HTTP-Endpunkt.

Wenn einer der oben genannten Punkte ein Problem darstellt oder Sie Kompatibilität mit älteren OpenResty-Versionen benötigen, empfehle ich, bei lua-resty-jwt zu bleiben.

Typen

Typen und Nullprüfungen werden mit umfangreicher Verwendung von EmmyLua-Anmerkungen bereitgestellt.

IDE-Plugin-Integrationen für EmmyLua: - Idea - VSCode

Die Datei ngx.d.lua im Stammverzeichnis des Projekts bietet einige ngx-Stubs.

Unterstützte Funktionen

  • JWS-Verifizierung: mit symmetrischen oder asymmetrischen Schlüsseln.
  • JWE-Entschlüsselung: mit symmetrischen oder asymmetrischen Schlüsseln.
  • Unterstützte Formate für asymmetrische Schlüssel:
  • PEM
  • DER
  • JWK
  • Validierung von JWT-Ansprüchen.
  • Automatisches Abrufen von JWKS und JWT-Validierung.
  • optionale Caching-Strategien.
  • Verschachtelte JWTs (JWS in JWE)

JWS-Verifizierung

Ansprüche Implementiert
alg ✅
jku ❌
jwk ❌
kid ✅
x5u ❌
x5c ❌
x5t ❌
x5t#S256 ❌
typ ✅
cty ❌
crit ✅
alg Implementiert JOSE Implementierungsanforderungen Anforderungen
HS256 ✅ Erforderlich
HS384 ✅ Optional
HS512 ✅ Optional
RS256 ✅ Empfohlen
RS384 ✅ Optional
RS512 ✅ Optional
ES256 ✅ Empfohlen+
ES384 ✅ Optional
ES512 ✅ Optional
PS256 ✅ Optional
PS384 ✅ Optional
PS512 ✅ Optional
none ❌ Optional
EdDSA ❌ Veraltet
ES256K ✅ Optional
Ed25519 ✅ Optional *OpenSSL 3.0+
Ed448 ✅ Optional

JWE-Entschlüsselung

Ansprüche Implementiert
alg ✅
enc ✅
zip ❌
jku ❌
jwk ❌
kid ✅
x5u ❌
x5c ❌
x5t ❌
x5t#S256 ❌
typ ✅
cty ✅
crit ✅
kty Implementiert JOSE Implementierungsanforderungen
EC ✅ Empfohlen+
RSA ✅ Erforderlich
oct ✅ Erforderlich
OKP ✅ Optional
alg Implementiert JOSE Implementierungsanforderungen Anforderungen
RSA1_5 ❌ Empfohlen-
RSA-OAEP ✅ Empfohlen+
RSA-OAEP-256 ✅ Optional
RSA-OAEP-384 ✅ Optional
RSA-OAEP-512 ✅ Optional
A128KW ✅ Empfohlen *OpenSSL 3.0+
A192KW ✅ Optional *OpenSSL 3.0+
A256KW ✅ Empfohlen *OpenSSL 3.0+
dir ✅ Empfohlen
ECDH-ES ✅ Empfohlen+
ECDH-ES+A128KW ✅ Empfohlen *OpenSSL 3.0+
ECDH-ES+A192KW ✅ Optional *OpenSSL 3.0+
ECDH-ES+A256KW ✅ Empfohlen *OpenSSL 3.0+
A128GCMKW ❌ Optional
A192GCMKW ❌ Optional
A256GCMKW ❌ Optional
PBES2-HS256+A128KW ❌ Optional
PBES2-HS384+A192KW ❌ Optional
PBES2-HS512+A256KW ❌ Optional

*Die erste offizielle Version von OpenResty, die OpenSSL 3.0+ enthält, ist OpenResty 1.27.1.1, die mit OpenSSL 3.0.15 ausgeliefert wurde (Ja, die schrecklich langsame OpenSSL 3.0-Serie...).

Daher sollten Sie bitte mindestens OpenResty 1.27.1.2 verwenden, das mit OpenSSL 3.4.1 ausgeliefert wurde.

enc Implementiert JOSE Implementierungsanforderungen
A128CBC-HS256 ✅ Erforderlich
A192CBC-HS384 ✅ Optional
A256CBC-HS512 ✅ Erforderlich
A128GCM ✅ Empfohlen
A192GCM ✅ Optional
A256GCM ✅ Empfohlen

JWKS-Abruf-Caching-Strategien

Cache-Strategie Implementiert
kein Cache ✅
lokal (shared_dict) ✅

JWT-Verifizierungsnutzung

jwt.decode_header_unsafe

syntax: header, err = jwt.decode_header_unsafe(token)

Liest einen JWT-Header und konvertiert ihn in eine Lua-Tabelle.

Wichtig: Diese Methode validiert nicht die JWT-Signatur! Verwenden Sie sie nur, wenn Sie den Header des Tokens inspizieren müssen, ohne die vollständige Validierung durchzuführen.

local jwt = require("resty.jwt-verification")

local token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE3MTY2NDkwNzJ9._MwFdsBPSyci9iARpoAaulReGcn1q7mKiPZjR2JDvdY"
local header, err = jwt.decode_header_unsafe(token)
if not header then
    return nil, "malformed jwt: " .. err
end
print("alg: " .. header.alg) -- alg: HS256

jwt.verify

syntax: decoded_token, err = jwt.verify(token, secret, options?)

Validiert ein JWS-Token und konvertiert es in eine Lua-Tabelle.

Der optionale Parameter options kann übergeben werden, um den Token-Validator zu konfigurieren. Gültige Felder sind: - valid_signing_algorithms (dict | nil): ein Dict, das erlaubte alg-Ansprüche enthält, die zur Validierung des JWT verwendet werden. - typ (string | nil): wenn nicht null, sicherstellen, dass der JWT-Anspruch typ mit dem übergebenen Wert übereinstimmt. - issuer (string | nil): wenn nicht null, sicherstellen, dass der JWT-Anspruch iss mit dem übergebenen Wert übereinstimmt. - audiences (string | table | nil): wenn nicht null, sicherstellen, dass der JWT-Anspruch aud mit einem der bereitgestellten Werte übereinstimmt. - subject (string | nil): wenn nicht null, sicherstellen, dass der JWT-Anspruch sub mit dem übergebenen Wert übereinstimmt. - jwtid (string | nil): wenn nicht null, sicherstellen, dass der JWT-Anspruch jti mit dem übergebenen Wert übereinstimmt. - ignore_not_before (bool): Wenn true, wird der JWT-Anspruch nbf ignoriert. - ignore_expiration (bool): Wenn true, wird der JWT-Anspruch exp ignoriert. - current_unix_timestamp (datetime | nil): die JWT-Ansprüche nbf und exp werden gegen diesen Zeitstempel validiert. Wenn null, wird das aktuelle Datum und die Uhrzeit verwendet, die von ngx.time() bereitgestellt werden. - timestamp_skew_seconds (int): Wie viele Sekunden Spielraum die Bibliothek verwenden kann, um die Token-Expiration gegen die aktuelle Zeit zu überprüfen. Nützlich, wenn Uhren nicht immer genau synchronisiert sind. Wenn dieser Wert zu hoch eingestellt wird, kann dies Sicherheitsprobleme verursachen.

Standardwerte für die Felder von options:

local verify_default_options = {
    valid_signing_algorithms = {
        ["HS256"]="HS256", ["HS384"]="HS384", ["HS512"]="HS512",
        ["RS256"]="RS256", ["RS384"]="RS384", ["RS512"]="RS512",
        ["ES256"]="ES256", ["ES384"]="ES384", ["ES512"]="ES512",
        ["PS256"]="PS256", ["PS384"]="PS384", ["PS512"]="PS512",
        ["ES256K"]="ES256K", ["Ed25519"]="Ed25519", ["Ed448"]="Ed448",
    },
    typ = nil,
    issuer = nil,
    audiences = nil,
    subject = nil,
    jwtid = nil,
    ignore_not_before = false,
    ignore_expiration = false,
    current_unix_timestamp = nil,
    timestamp_skew_seconds = 1,
}

Minimalbeispiel mit symmetrischen Schlüsseln:

local jwt = require("resty.jwt-verification")

local token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE3MTY2NTUwMTV9.NuEhIzUuufJgPZ8CmCPnD4Vrw7EnTyWD8bGtYCwuDZ0"
local decoded_token, err = jwt.verify(token, "superSecretKey")
if not decoded_token then
    return nil, "invalid jwt: " .. err
end
print(decoded_token.header.alg) -- HS256
print(decoded_token.payload.foo) -- bar

Minimalbeispiel mit asymmetrischen Schlüsseln:

local jwt = require("resty.jwt-verification")

local token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE3MTY2Njg2Mzd9.H6PE-zLizMMqefx8DG4X5glVjyxR9UNT225Tq2yufHhu4k9K0IGttpykjMCG8Ck_4Qt2ezEWIgoiWhSn1rv_zwxe7Pv-B09fDs7h1hbASi5MZ0YVAmK9ID1RCKM_NTBEnPLot_iopKZRj2_J5F7lvXwJDZSzEAFJZdrgjKeBS4saDZAv7SIL9Nk75rdhgY-RgRwsjmTYSksj7eioRJJLHifrMnlQDbdrBD5_Qk5tD6VPcssO-vIVBUAYrYYTa7M7A_v47UH84zDtzNYBbk9NrDbyq5-tYs0lZwNhIX8t-0VAxjuCyrrGZvv8_O01pdi90kQmntFIbaiDiD-1WlGcGA"
local decoded_token, err = jwt.verify(token, "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvXFhNyhFWuWtFSJqfOAw\np42lLIn9kB9oaciiKgNAYZ8SYw5t9Fo+Zh7IciVijn+cVS2/aoBNg2HhfdYgfpQ/\nsb6jwbRqFMln2GmG+X2aJ2wXMJ/QfxrPFdO9L36bAEwkubUTYXwgMSm1KqWRN8xX\n+oBu+dbyzw7iUbrmw0ybzXKZLJvetCvmt0reU5TvdwoczOWFBSKeYnzBrC6hISD8\n8TYDJ4tiw1EWVOupQGqgel0KjC7iwdIYi7PROn6/1MMnF48zlBbT/7/zORj84Z/y\nDnmxZu1MQ07kHqXDRYumSfCerg5Xw5vde7Tz8O0TWtaYV3HJXNa0VpN5OI3L4y7P\nhwIDAQAB\n-----END PUBLIC KEY-----")
if not decoded_token then
    return nil, "invalid jwt: " .. err
end
print(decoded_token.header.alg) -- RS256
print(decoded_token.payload.foo) -- bar

Beispiele mit benutzerdefinierten options:

local jwt = require("resty.jwt-verification")

local token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE3MTY2NTUwMTV9.NuEhIzUuufJgPZ8CmCPnD4Vrw7EnTyWD8bGtYCwuDZ0"
local decoded_token, err = jwt.verify(token, "superSecretKey", {
    valid_signing_algorithms = {["HS256"]="HS256", ["HS384"]="HS384", ["HS512"]="HS512"}, -- nur HS-Familien-Algorithmen zulassen
    audiences = {"user", "admin"}, -- `aud` muss einer der folgenden sein
    ignore_not_before = true -- `nbf`-Anspruch ignorieren (nicht empfohlen)
})
if not decoded_token then
    return nil, "invalid jwt: " .. err
end
print(decoded_token.header.alg) -- HS256
print(decoded_token.payload.foo) -- bar

jwt.decrypt

syntax: decoded_token, err = jwt.decrypt(token, secret, options?)

Entschlüsseln und validieren Sie ein JWE-Token und konvertieren Sie es in eine Lua-Tabelle.

Der optionale Parameter options kann übergeben werden, um den Token-Validator zu konfigurieren. Gültige Felder sind: - valid_encryption_alg_algorithms (dict | nil): ein Dict, das erlaubte alg-Ansprüche enthält, die zur Entschlüsselung des JWT verwendet werden. - valid_encryption_enc_algorithms (dict | nil): ein Dict, das erlaubte enc-Ansprüche enthält, die zur Entschlüsselung des JWT verwendet werden. - typ (string | nil): wenn nicht null, sicherstellen, dass der JWT-Anspruch typ mit dem übergebenen Wert übereinstimmt. - issuer (string | nil): wenn nicht null, sicherstellen, dass der JWT-Anspruch iss mit dem übergebenen Wert übereinstimmt. - audiences (string | table | nil): wenn nicht null, sicherstellen, dass der JWT-Anspruch aud mit einem der bereitgestellten Werte übereinstimmt. - subject (string | nil): wenn nicht null, sicherstellen, dass der JWT-Anspruch sub mit dem übergebenen Wert übereinstimmt. - jwtid (string | nil): wenn nicht null, sicherstellen, dass der JWT-Anspruch jti mit dem übergebenen Wert übereinstimmt. - ignore_not_before (bool): Wenn true, wird der JWT-Anspruch nbf ignoriert. - ignore_expiration (bool): Wenn true, wird der JWT-Anspruch exp ignoriert. - current_unix_timestamp (datetime | nil): die JWT-Ansprüche nbf und exp werden gegen diesen Zeitstempel validiert. Wenn null, wird das aktuelle Datum und die Uhrzeit verwendet, die von ngx.time() bereitgestellt werden. - timestamp_skew_seconds (int): Wie viele Sekunden Spielraum die Bibliothek verwenden kann, um die Token-Expiration gegen die aktuelle Zeit zu überprüfen. Nützlich, wenn Uhren nicht immer genau synchronisiert sind. Wenn dieser Wert zu hoch eingestellt wird, kann dies Sicherheitsprobleme verursachen. - allow_nested_jwt (bool): Erlaubt die Verifizierung von JWTs, die ein anderes JWT enthalten (auch bekannt als verschachtelte JWTs oder JWT-in-JWT). Dies ist standardmäßig optional, da die zu validierenden Ansprüche immer innerhalb des innersten JWTs liegen und NICHT automatisch validiert werden. Es liegt an Ihnen, die inneren JWTs, die als String im payload-Feld von dieser Bibliothek zurückgegeben werden, rekursiv zu validieren. Ein verschachteltes JWT MUSS den Header-Schlüssel cty auf JWT setzen, um als solches erkannt zu werden.

Standardwerte für die Felder von options:

local decrypt_default_options = {
    valid_encryption_alg_algorithms = {
        ["RSA-OAEP"]="RSA-OAEP",
        ["RSA-OAEP-256"]="RSA-OAEP-256", ["RSA-OAEP-384"]="RSA-OAEP-384", ["RSA-OAEP-512"]="RSA-OAEP-512",
        ["A128KW"]="A128KW", ["A192KW"]="A192KW", ["A256KW"]="A256KW",
        ["dir"]="dir",
        ["ECDH-ES"]="ECDH-ES",
        ["ECDH-ES+A128KW"]="ECDH-ES+A128KW",
        ["ECDH-ES+A192KW"]="ECDH-ES+A192KW",
        ["ECDH-ES+A256KW"]="ECDH-ES+A256KW",
    },
    valid_encryption_enc_algorithms = {
        ["A128CBC-HS256"]="A128CBC-HS256",
        ["A192CBC-HS384"]="A192CBC-HS384",
        ["A256CBC-HS512"]="A256CBC-HS512",
        ["A128GCM"]="A128GCM",
        ["A192GCM"]="A192GCM",
        ["A256GCM"]="A256GCM",
    },
    typ = nil,
    issuer = nil,
    audiences = nil,
    subject = nil,
    jwtid = nil,
    ignore_not_before = false,
    ignore_expiration = false,
    current_unix_timestamp = nil,
    timestamp_skew_seconds = 1,
    allow_nested_jwt = false,
}

Minimalbeispiel mit symmetrischen Schlüsseln:

local jwt = require("resty.jwt-verification")

local token = "eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.zAIq7qVAEO-eCG6gOdd3ld8_IHzeq3UlaWLHF2IDn6nNUuHh5n_i4w.5CM864cgiBgFPwluW4ViRg.mUeX7zHDVNsXhys0XO5S4w.t3yAR_HU0GDTEyCbpRa6BQ"
local decoded_token, err = jwt.decrypt(token, "superSecretKey12")
if not decoded_token then
    return nil, "invalid jwt: " .. err
end
print(decoded_token.header.alg) -- A128KW
print(decoded_token.header.enc) -- A128CBC-HS256
print(decoded_token.payload.foo) -- bar

Minimalbeispiel mit asymmetrischen Schlüsseln im PEM-Format:

local jwt = require("resty.jwt-verification")

local token = "eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkEyNTZHQ00iLCJlcGsiOnsieCI6IkFJdkVhSzVKZGl6d1I5ZFMzRUN2Y0dKMGNHWXNFejdpYWJwRUp1bE0tWDAiLCJjcnYiOiJYMjU1MTkiLCJrdHkiOiJPS1AifX0.QFfmPVYjk1PoyhE7elaDgUdUGGeAECLo7jB4ghq_8MIRXV3VKO1yAA.XITF2apHB5roeUsx.08T0gALwkb6Wibr2Og.IJoh3U_tspnMx_mWelRT5g"
local decoded_token, err = jwt.decrypt(token, "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VuBCIEIMCxXl/FEuh3pGo1Z++QRs2vudqkGd63mK0Js0f6y+55\n-----END PRIVATE KEY-----", nil)
if not decoded_token then
    return nil, "invalid jwt: " .. err
end
print(decoded_token.header.alg) -- ECDH-ES+A128KW
print(decoded_token.header.enc) -- A256GCM
print(decoded_token.payload.foo) -- bar

Beispiele mit benutzerdefinierten options:

local jwt = require("resty.jwt-verification")

local token = "eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0.zAIq7qVAEO-eCG6gOdd3ld8_IHzeq3UlaWLHF2IDn6nNUuHh5n_i4w.5CM864cgiBgFPwluW4ViRg.mUeX7zHDVNsXhys0XO5S4w.t3yAR_HU0GDTEyCbpRa6BQ"
local decoded_token, err = jwt.decrypt(token, "superSecretKey12", {
    valid_encryption_alg_algorithms = {["A128KW"]="A128KW"}, -- nur A128KW-Familienalgorithmen zulassen (benötigt OpenSSL 3.0+)
    valid_encryption_enc_algorithms = {["A128CBC-HS256"]="A128CBC-HS256"}, -- nur A128CBC-Familienverschlüsselungen zulassen
    audiences = {"user", "admin"}, -- `aud` muss einer der folgenden sein
    ignore_not_before = true -- `nbf`-Anspruch ignorieren (nicht empfohlen)
})
if not decoded_token then
    return nil, "invalid jwt: " .. err
end
print(decoded_token.header.alg) -- A128KW
print(decoded_token.header.enc) -- A128CBC-HS256
print(decoded_token.payload.foo) -- bar

JWKS-Verifizierungsnutzung

Das Modul resty.jwt-verification-jwks implementiert das automatische Abrufen von JWKS von einem HTTP-Endpunkt und die anschließende JWT-Validierung mit den abgerufenen Schlüsseln.

Die Module resty.jwt-verification-jwks-cache-* implementieren optionale JWKS-Caching-Strategien. Es kann immer nur eine Caching-Strategie aktiviert werden; wenn keine aktiviert ist, wird der JWKS-Endpunkt einmal für jedes zu validierende JWT aufgerufen.

jwks.init

syntax: ok, err = jwks.init(cache_strategy?)

Initialisiert das jwks-Modul und optional eine Caching-Strategie angeben.

Diese Funktion muss nur einmal aufgerufen werden und vorzugsweise im Abschnitt init_by_lua_file.

local jwks = require("resty.jwt-verification-jwks")

-- ohne Cache initialisieren
local ok, err = jwks.init(nil)
if not ok then
    ngx.say("Fehler bei der Initialisierung des jwks-Moduls: ", err)
end

-- oder ...

-- mit lokalem Cache basierend auf dem OpenResty Shared Memory-Dict initialisieren.
-- Fügen Sie dies im `http`-Abschnitt Ihrer NGINX-Konfiguration hinzu: `lua_shared_dict resty_jwt_verification_cache_jwks 10m;`
-- siehe https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/#ngxshareddict
local jwks_cache_local = require("resty.jwt-verification-jwks-cache-local")
local ok, err = jwks.init(jwks_cache_local)
if not ok then
    ngx.say("Fehler bei der Initialisierung des jwks-Moduls: ", err)
end

Sie können auch Ihren eigenen Cache implementieren und ihn in der Init-Methode übergeben. Hier ist ein Beispiel, wie:

local my_cache = {}

---Holen Sie sich den zwischengespeicherten Eintragstring für den Schlüssel.
---@param key string Cache-Schlüssel.
---@return string|nil value Gibt das zwischengespeicherte Ergebnis als String zurück, wenn vorhanden, andernfalls nil.
function my_cache.get(key)
    -- TODO
end

---Zwischenspeichern von Daten unter dem Schlüssel bis zum Ablauf.
---@param key string Cache-Schlüssel.
---@param value string Cache-Wert.
---@param expiry integer Ablauf des Cache-Eintrags in Sekunden.
---@return boolean|nil ok true bei Erfolg
---@return string|nil err nil bei Erfolg, andernfalls Fehlermeldung.
function my_cache.setex(key, value, expiry)
    -- TODO
end

local ok, err = jwks.init(my_cache)
if not ok then
    ngx.say("Fehler bei der Initialisierung des jwks-Moduls: ", err)
end

jwks.set_http_timeouts_ms

syntax: jwks.set_http_timeouts_ms(connect, send, read)

Setzt die HTTP-Client-Timeouts in Millisekunden, die zum Abrufen von JWKS verwendet werden.

local jwks = require("resty.jwt-verification-jwks")

jwks.set_http_timeouts_ms(5000, 5000, 5000)

jwks.set_http_ssl_verify

syntax: jwks.set_http_ssl_verify(enabled)

Aktiviert/deaktiviert die TLS-Überprüfung, die vom HTTP-Client zum Abrufen von JWKS verwendet wird.

Standardmäßig werden alle TLS-Zertifikate überprüft. Wenn der JWKS-Endpunkt selbstsignierte Zertifikate verwendet, fügen Sie entweder die jeweilige Root-CA zum OS-Zertifikatsspeicher hinzu oder deaktivieren Sie die Zertifikatsüberprüfung für diesen Endpunkt (das ist unsicher).

local jwks = require("resty.jwt-verification-jwks")

jwks.set_http_ssl_verify(false)

jwks.set_cache_ttl

syntax: jwks.set_http_ssl_verify(enabled)

Ändert die Standard-Cache-TTL. Der Standardwert beträgt 12 Stunden.

Hinweis: Die Cache-TTL kann nur verwendet werden, wenn das jwks-Modul mit einem Cache initialisiert wurde. Siehe wie man Caching aktiviert.

local jwks = require("resty.jwt-verification-jwks")

jwks.set_cache_ttl(2 * 3600) -- 2h

jwks.fetch_jwks

syntax: payload, err = jwks.fetch_jwks(endpoint)

Holt manuell JWKS von einem HTTP-Endpunkt ab; das zurückgegebene Payload ist im Erfolgsfall der HTTP-Antwortkörper als String: Es wird keinerlei Überprüfung durchgeführt, ob das Payload JWKS oder etwas anderes enthält.

Wenn eine Caching-Strategie aktiviert wurde, wird der Endpunkt zuerst versuchen, es aus dem Cache abzurufen. Nach einem Cache-Miss und erfolgreichem JWKS-Abruf über HTTP wird der Cache mit dem Ergebnis aktualisiert.

local jwks = require("resty.jwt-verification-jwks")

payload, err = jwks.fetch_jwks("https://www.googleapis.com/oauth2/v3/certs")
if payload == nil then
    print("Fehler beim Abrufen von JWKS: ", err)
    return
end
print(payload) -- '{"keys":[{"alg":"RS256","e":"AQAB","kid":"882503a5fd56e9f734dfba5c50d7bf48db284ae9","kty":"RSA","n":"woRUr445_ODXrFeynz5L208aJkABOKQHEzbfGM_V1ijkYZWZKY0PXKPP_wRKcE4C6OyjDNd5gHh3dF5QsVhVDZCfR9QjTf94o4asngrHzdOcfQ0pZIvzu_vzaVG82VGLM-2rKQp8uz06A6TbUzbIv9wQ8wQpYDIdujNkLqL22Mkb2drPxm9Y9I05PmVdkkvAbu4Q_KRJWxykOigHp-hVBmpYS2P3xuX56gM7ZRcXXJKKUfrGel4nDhSIAAD1wBNcVVgKbb0TYfZmVpRSCji_b6JHjqYhYjUasdotYJzWl7quAFsN_X_4j-cHZ30OS81j--OiIxWpL11y1kcbE0u-Dw","use":"sig"},{"n":"m7GlcF1ExRB4braT7sDnZvlY3wpqX9krkVRqcVA-m43FWFYBtuSpd-lc0EV8R8TO180y0tSgJc7hviI1IBJQlNa7XkjVGhY0ZFUp5rTpC45QbA9Smo4CLa5HQIf-69rkkovjFNMuDQvNiYCgRPLyRjmQbN2uHl4fU3hhf5qFqKTKo7eLCZiEMjrOkTXziA7xJJigUGe-ab8U-AXNH1fnCbejzHEIxL0eUG_4r4xddImOxETDO5T65AQCeqs7vtYos2xq5SLFuaUsithRQ-IMm3OlcVhMjBYt6uvGS6IdMjKon4wThCxEqAEXg0nahiGjnQCW176SNF152__TOjQVwQ","alg":"RS256","kty":"RSA","use":"sig","kid":"8e8fc8e556f7a76d08d35829d6f90ae2e12cfd0d","e":"AQAB"}]}'

jwks.verify_jwt_with_jwks

syntax: jwt, err = jwks.verify_jwt_with_jwks(jwt_token, jwks_endpoint, jws_options?)

Gegeben ein signiertes jwt_token als String, verifizieren Sie seine Signatur mit JWKS, die vom HTTP-Dienst bereitgestellt werden, der unter jwks_endpoint gefunden wird.

Im Erfolgsfall wird das verifizierte JWT als Lua-Tabelle zurückgegeben, andernfalls werden nil und ein Fehler zurückgegeben.

Der optionale Parameter jws_options kann übergeben werden, um den Token-Validator zu konfigurieren, wenn jwt.verify aufgerufen wird, nachdem die JWKS erfolgreich abgerufen wurden. Siehe die entsprechenden Dokumente zu jwt.verify für weitere Informationen darüber, welche Optionen übergeben werden können.

local jwks = require("resty.jwt-verification-jwks")

jwt, err = jwks.verify_jwt_with_jwks("<MY_JWT>", "http://myservice:8888/.well-known/jwks.json", nil)
if jwt == nil then
    print("Fehler bei der Verifizierung des JWT: ", err)
    return
end
print(jwt.header.alg)
print(tostring(jwt.payload))

jwks.decrypt_jwt_with_jwks

syntax: jwt, err = jwks.decrypt_jwt_with_jwks(jwt_token, jwks_endpoint, jwe_options?)

Gegeben ein verschlüsseltes jwt_token als String, entschlüsseln Sie es mit JWKS, die vom HTTP-Dienst bereitgestellt werden, der unter jwks_endpoint gefunden wird.

Im Erfolgsfall wird das entschlüsselte JWT als Lua-Tabelle zurückgegeben, andernfalls werden nil und ein Fehler zurückgegeben.

Der optionale Parameter jwe_options kann übergeben werden, um den Token-Validator zu konfigurieren, wenn jwt.decrypt aufgerufen wird, nachdem die JWKS erfolgreich abgerufen wurden. Siehe die entsprechenden Dokumente zu jwt.decrypt für weitere Informationen darüber, welche Optionen übergeben werden können.

local jwks = require("resty.jwt-verification-jwks")

jwt, err = jwks.decrypt_jwt_with_jwks("<MY_JWT>", "http://myservice:8888/.well-known/jwks.json", nil)
if jwt == nil then
    print("Fehler beim Entschlüsseln des JWT: ", err)
    return
end
print(jwt.header.alg)
print(jwt.header.enc)
print(tostring(jwt.payload))

Verwendete RFCs als Referenz

Tests ausführen

Einrichtung

Installieren Sie das Test-Framework:

sudo cpan Test::Nginx

Installieren Sie OpenResty: siehe https://openresty.org/en/linux-packages.html

Ausführen

export PATH=/usr/local/openresty/nginx/sbin:$PATH
prove -r t

Benchmarks ausführen

Das Testsuite Test::Nginx hat eine integrierte Benchmarking-Integration mit weighttp.

Erhöhen Sie die sysctl-Limits

Wenn Sie die Bibliothek stresse testen möchten, müssen Sie möglicherweise die Systemlimits erhöhen.

cat > /etc/sysctl.d/openresty-benchmarks.conf << EOF
net.ipv4.ip_local_port_range=2048 65535

net.ipv4.tcp_tw_reuse=1

net.core.netdev_max_backlog=2000
net.ipv4.tcp_max_syn_backlog=2048
EOF

## Änderungen anwenden
sudo sysctl -p /etc/sysctl.d/openresty-benchmarks.conf

Tests starten

Ich habe einige pseudo-reale Szenarien im Ordner benchmarks erstellt.

## Weitere Informationen zur Syntax: https://openresty.gitbooks.io/programming-openresty/content/testing/test-modes.html
export TEST_NGINX_BENCHMARK='50000 10'
prove -r ./benchmarks

Standardmäßig wird nur 1 NGINX-Arbeiter und 1 CPU-Kern verwendet, um die Benchmarks durchzuführen. Um die Arbeiterlimits zu erhöhen, ändern Sie die Direktive workers(1); in den .t-Dateien und führen Sie den Benchmark erneut aus.

GitHub

Sie finden möglicherweise zusätzliche Konfigurationstipps und Dokumentationen für dieses Modul im GitHub-Repository für nginx-module-jwt-verification.