Zum Inhalt springen
ecdsa.com
PHP

firebase/php-jwt

firebase/php-jwt, das meistinstallierte JWT-Paket für PHP: ein Objekt Key, das den Algorithmus festlegt, Ablehnung kurzer HMAC-Schlüssel, aber kein ES512 oder PS384/512, keine Prüfung von Aussteller oder Audience und ES256 auch mit P-384-Schlüsseln.
Lizenz
BSD-3-Clause
Geprüfte Version
7.2.1 ·
Quellcode
github.com/firebase/php-jwt
Dokumentation
github.com/firebase/php-jwt#readme

Kompatibilität auf einen Blick

JOSE und JWT

JWS-Algorithmen
HS256HS384HS512RS256RS384RS512ES256ES384ES256KEdDSA

php-jwt kodiert und dekodiert Tokens mit JWT::encode() und JWT::decode() auf Basis der openssl-Erweiterung und von libsodium. Seit Version 6 ist ein Objekt Key – Schlüsselmaterial plus Algorithmus – Pflicht, sodass der Algorithmus aus deinem Code kommt, nicht aus dem Token: Ein RS256-Token und ein mit dem PEM-Text des EC-Schlüssels gefälschtes HS256-Token scheiterten beide an new Key($pem, 'ES256') mit Incorrect key for this algorithm, und ein unsigniertes Token scheitert mit Algorithm not supported. Dieser Schutz greift nur, solange die Anwendung das Objekt Key selbst erstellt; mit new Key($pem, 'HS256') bestand das gefälschte Token die Prüfung.

Version 7.2.1 unterstützt HS256/384/512, RS256/384/512, ES256, ES384, ES256K und EdDSA. ES512 wird nicht unterstützt (Algorithm not supported), PS256 setzt ein installiertes phpseclib/phpseclib voraus, und PS384 und PS512 sind gar nicht verfügbar – für Tokens von Ausstellern, die diese Algorithmen verwenden, brauchst du web-token oder lcobucci/jwt. HMAC-Schlüssel, die kürzer als der Hash sind, werden abgelehnt (Provided key is too short).

ES256 ist nicht an P-256 gebunden: Ein Token, das mit einem P-384-Schlüssel und ES256 im Header signiert war, wurde von der Bibliothek selbst erzeugt und akzeptiert, obwohl andere Bibliotheken es ablehnen. ES256-Signaturen werden in das 64 Byte lange rohe r‖s umgewandelt, das JWS verlangt; eine DER-Signatur scheitert mit Signature verification failed. Prüfe die Signatur eines Tokens im JWT-Debugger.

Die Behandlung von Claims ist minimal. exp, nbf und iat werden nur geprüft, wenn sie vorhanden sind, JWT::$leeway ist eine globale statische Variable mit dem Standardwert 0, und eine Prüfung von Aussteller oder Audience gibt es überhaupt nicht – das Beispiel prüft exp und iss selbst. Für die Prüfung über JWKS wandelt JWK::parseKeySet() einen Schlüsselsatz in Objekte vom Typ Key um; untersuche den Schlüsselsatz eines Anbieters mit dem JWKS-Checker.

Fakten und die Prüfungen dahinter

Nichts im Folgenden ist aus einer Dokumentation abgeschrieben. Das Prüfskript content/libraries/verify/firebase-php-jwt/run.sh hat firebase/php-jwt 7.2.1 am 20. Oktober 2026 im Container-Image php:8.5.11-cli-trixie ausgeführt; die Seite muss mit seiner Ausgabe übereinstimmen, und jeder Fakt führt die zugehörigen Zeilen auf.

  • JWS-Algorithmen

    HS256HS384HS512RS256RS384RS512ES256ES384ES256KEdDSA

    Signieren und Prüfen funktionierten mit HS256/384/512, RS256/384/512, ES256, ES384, ES256K und EdDSA; ES512 und PS384/512 werden nicht unterstützt, und PS256 setzt phpseclib voraus.

    Von der Prüfung aufgezeichnet
    fact jws-algorithms = HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES256K, EdDSA
    evidence jws-algorithms: PS256: DomainException: phpseclib/phpseclib is required for PS256 support
    evidence jws-algorithms: PS384: DomainException: Algorithm not supported
    evidence jws-algorithms: PS512: DomainException: Algorithm not supported
    evidence jws-algorithms: ES512: DomainException: Algorithm not supported
    evidence jws-algorithms: Ed25519: no key family
  • Kodierung von ES256-Signaturen

    raw

    ES256-Signaturen bestehen aus 64 Byte rohem r‖s.

    Von der Prüfung aufgezeichnet
    fact jws-ecdsa-encoding = raw
  • DER-Signatur in einer JWS

    rejected

    Eine DER-kodierte ES256-Signatur scheitert mit SignatureInvalidException: Signature verification failed.

    Von der Prüfung aufgezeichnet
    fact jws-der-signature = rejected
    evidence jws-der-signature: Firebase\JWT\SignatureInvalidException: Signature verification failed
  • Allowlist der Algorithmen

    required

    decode() verlangt ein Objekt Key mit Algorithmus; ein bloßer Schlüssel-String scheitert, und ein RS256-Token scheitert an new Key($ecPem, 'ES256') mit Incorrect key for this algorithm.

    Von der Prüfung aufgezeichnet
    fact jwt-algorithm-allowlist = required
    evidence jwt-algorithm-allowlist: RS256 token against new Key(EC PEM, 'ES256'): UnexpectedValueException: Incorrect key for this algorithm
    evidence jwt-algorithm-allowlist: decode() with a bare key string: UnexpectedValueException: "kid" empty, unable to lookup correct key
  • Unsignierte Tokens (alg none)

    rejected

    Ein unsigniertes Token scheitert mit Algorithm not supported.

    Von der Prüfung aufgezeichnet
    fact jwt-alg-none = rejected
    evidence jwt-alg-none: UnexpectedValueException: Algorithm not supported
  • Öffentlicher Schlüssel als HMAC-Secret

    rejected

    Ein HS256-Token mit dem PEM-Text als Schlüssel scheiterte am Key für ES256, doch mit new Key($pem, 'HS256') bestand es die Prüfung.

    Von der Prüfung aufgezeichnet
    fact jwt-hmac-public-key = rejected
    evidence jwt-hmac-public-key: Key(PEM, 'ES256'): UnexpectedValueException: Incorrect key for this algorithm
    evidence jwt-hmac-public-key: Key(PEM, 'HS256') built by the application: ok
  • Abgleich der Kurve mit alg

    not-enforced

    Ein Token, das unter ES256 mit einem P-384-Schlüssel signiert war, ließ sich erzeugen und bestand die Prüfung.

    Von der Prüfung aufgezeichnet
    fact jwt-ecdsa-curve-check = not-enforced
    evidence jwt-ecdsa-curve-check: ok
  • Standardtoleranz für Uhrabweichungen

    0s

    JWT::$leeway ist 0: Ein Token, das drei Sekunden zuvor abgelaufen war, wurde abgelehnt.

    Von der Prüfung aufgezeichnet
    fact jwt-clock-skew = 0s
    evidence jwt-clock-skew: JWT::$leeway = 0
  • Ablauf-Claim erforderlich

    no

    Ein Token ohne exp wurde erfolgreich dekodiert.

    Von der Prüfung aufgezeichnet
    fact jwt-exp-required = no
  • Kurzes HMAC-Secret

    rejected

    Ein HS256-Schlüssel mit 5 Byte scheitert mit Provided key is too short.

    Von der Prüfung aufgezeichnet
    fact jwt-hmac-short-secret = rejected
    evidence jwt-hmac-short-secret: 5-byte HS256 key: DomainException: Provided key is too short

Verwendung

Stelle ein ES256-Token aus, dekodiere es mit 30 Sekunden Toleranz (Leeway) und einem Key, der den Algorithmus festlegt, und prüfe exp und iss explizit.
<?php
require 'vendor/autoload.php';

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

$private = openssl_pkey_new(['private_key_type' => OPENSSL_KEYTYPE_EC, 'curve_name' => 'prime256v1']);
$publicPem = openssl_pkey_get_details($private)['key'];

$token = JWT::encode(['sub' => 'user-42', 'iss' => 'https://auth.example.com', 'exp' => time() + 600], $private, 'ES256');

// The Key object pins the algorithm; leeway is a static setting, 0 by default.
JWT::$leeway = 30;
$claims = JWT::decode($token, new Key($publicPem, 'ES256'));

// php-jwt checks exp/nbf/iat only when present and never checks iss or aud: do it here.
if (!isset($claims->exp) || $claims->iss !== 'https://auth.example.com') {
    throw new UnexpectedValueException('unexpected claims');
}
echo 'sub: ', $claims->sub, "\n";

Die Snippet-Testumgebung führt jedes Beispiel unverändert im Container-Image php:8.5.11-cli-trixie aus, und der Lauf schlägt fehl, wenn die Ausgabe nicht übereinstimmt.

Einrichtung
curl -fsSL -o /tmp/composer.phar https://getcomposer.org/download/2.10.3/composer.phar && echo '7a2d379d5b8ffdaa028580ef26494c36d2feef4b178d3dd1473a4dbc5e17c8d6 /tmp/composer.phar' | sha256sum -c - >/dev/null && apt-get -qq update >/dev/null && apt-get -qq install -y unzip >/dev/null 2>&1 && COMPOSER_ALLOW_SUPERUSER=1 php /tmp/composer.phar require --quiet firebase/php-jwt:7.2.1
Befehl
php usage.php
Ausgabe muss passen (regulärer Ausdruck)
sub: user-42

Bibliotheken