HS* JWT -Algorithmen) BeispielRS* , PS* , ES* und EdDSA -Algorithmen) Beispielboring KisteEine neue JWT -Implementierung (JSON Web Tokens) für Rust, die sich auf Einfachheit konzentriert und gleichzeitig gemeinsame JWT -Sicherheits -Fallstricke vermeidet.
jwt-simple ist nicht optimiert und unterstützt alle häufig bereitgestellten Authentifizierungs- und Signaturalgorithmen:
| JWT -Algorithmus Name | Beschreibung |
|---|---|
HS256 | HMAC-SHA-256 |
HS384 | HMAC-SHA-384 |
HS512 | HMAC-SHA-512 |
BLAKE2B | Blake2b-256 |
RS256 | RSA mit PKCS#1v1.5 Polster / SHA-256 |
RS384 | RSA mit PKCS#1v1.5 Polster / SHA-384 |
RS512 | RSA mit PKCS#1v1.5 Polster / SHA-512 |
PS256 | RSA mit PSS-Polsterung / SHA-256 |
PS384 | RSA mit PSS-Polsterung / SHA-384 |
PS512 | RSA mit PSS-Polsterung / SHA-512 |
ES256 | ECDSA über P256 / SHA-256 |
ES384 | ECDSA über P384 / SHA-384 |
ES256K | ECDSA über SECP256K1 / SHA-256 |
EdDSA | Ed25519 |
jwt-simple kann aus der Box zu WebAssembly/WASI zusammengestellt werden. Es ist vollständig kompatibel mit dem schnell berechneten Service.
Wichtig: Der Zweck von JWT ist es, zu überprüfen, ob eine Partei Daten erstellt wurde, die einen geheimen Schlüssel kennt. Es bietet keine Vertraulichkeit: JWT -Daten werden einfach als Base64 codiert und nicht verschlüsselt.
cargo.toml :
[ dependencies ]
jwt-simple = " 0.12 "Rost:
use jwt_simple :: prelude :: * ; Fehler werden als jwt_simple::Error Fehlerwerte zurückgegeben (Alias für den Error der thiserror -Kiste).
HS* JWT -Algorithmen) BeispielAuthentifizierungsschemata verwenden den gleichen Schlüssel zum Erstellen und Überprüfen von Token. Mit anderen Worten, beide Parteien müssen sich letztendlich gegenseitig vertrauen, oder der Überprüfer könnte auch willkürliche Token erzeugen.
Schlüsselerstellung:
use jwt_simple :: prelude :: * ;
// create a new key for the `HS256` JWT algorithm
let key = HS256Key :: generate ( ) ; Ein Schlüssel kann als Bytes mit key.to_bytes() exportiert und mit HS256Key::from_bytes() wiederhergestellt werden.
Token -Schöpfung:
/// create claims valid for 2 hours
let claims = Claims :: create ( Duration :: from_hours ( 2 ) ) ;
let token = key . authenticate ( claims ) ? ;-> fertig!
let claims = key . verify_token :: < NoCustomClaims > ( & token , None ) ? ;-> fertig! Keine zusätzlichen Schritte erforderlich.
Die wichtigsten Ablaufzeit, die Startzeit, die Authentifizierungs -Tags usw. werden automatisch überprüft. Die Funktion schlägt mit JWTError::InvalidAuthenticationTag fehl, wenn das Authentifizierungs -Tag für den angegebenen Schlüssel ungültig ist.
Die vollständige Auseinandersetzung mit Ansprüchen kann gegebenenfalls im claims inspiziert werden. NoCustomClaims bedeutet, dass nur die Standard-Ansprüche von der Anwendung verwendet werden, aber auch anwendungsdefinierte Ansprüche unterstützt werden können.
Zusätzliche Überprüfungsschritte können optional über die ValidationOptions -Struktur aktiviert werden:
let mut options = VerificationOptions :: default ( ) ;
// Accept tokens that will only be valid in the future
options . accept_future = true ;
// Accept tokens even if they have expired up to 15 minutes after the deadline,
// and/or they will be valid within 15 minutes.
// Note that 15 minutes is the default, since it is very common for clocks to be slightly off.
options . time_tolerance = Some ( Duration :: from_mins ( 15 ) ) ;
// Reject tokens if they were issued more than 1 hour ago
options . max_validity = Some ( Duration :: from_hours ( 1 ) ) ;
// Reject tokens if they don't include an issuer from that set
options . allowed_issuers = Some ( HashSet :: from_strings ( & [ "example app" ] ) ) ;
// see the documentation for the full list of available options
let claims = key . verify_token :: < NoCustomClaims > ( & token , Some ( options ) ) ? ; Beachten Sie, dass allowed_issuers und zulässige und allowed_audiences keine Zeichenfolgen, sondern Zeichensätze (unter Verwendung des HashSet -Typs aus der Rust -Standardbibliothek) sind, da die Anwendung mehrere Rückgabeteile zulassen kann.
RS* , PS* , ES* und EdDSA -Algorithmen) BeispielEine Signatur erfordert ein Schlüsselpaar: ein geheimer Schlüssel zum Erstellen von Token und einen öffentlichen Schlüssel, der sie nur überprüfen kann.
Verwenden Sie immer ein Signaturschema, wenn beide Parteien sich letztendlich nicht gegenseitig vertrauen, z. B. Token, die zwischen Kunden und API -Anbietern ausgetauscht werden.
Schlüsselerstellung:
use jwt_simple :: prelude :: * ;
// create a new key pair for the `ES256` JWT algorithm
let key_pair = ES256KeyPair :: generate ( ) ;
// a public key can be extracted from a key pair:
let public_key = key_pair . public_key ( ) ; use jwt_simple :: prelude :: * ;
// create a new key pair for the `ES384` JWT algorithm
let key_pair = ES384KeyPair :: generate ( ) ;
// a public key can be extracted from a key pair:
let public_key = key_pair . public_key ( ) ;Tasten können als Bytes für die spätere Wiederverwendung exportiert und aus Bytes oder für RSA aus einzelnen Parametern, Der-codierten Daten oder pEM-kodierten Daten importiert werden.
Erstellung von RSA -Schlüsselpaaren unter Verwendung von OpenSSL- und PEM -Einfuhr des geheimen Schlüssels:
openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -outform PEM -pubout -out public.pem let key_pair = RS384KeyPair :: from_pem ( private_pem_file_content ) ? ;
let public_key = RS384PublicKey :: from_pem ( public_pem_file_content ) ? ; Die Erstellung und Überprüfung der Token funktionieren genauso wie bei HS* -Algorithmen, außer dass Token mit einem Schlüsselpaar erstellt und unter Verwendung des entsprechenden öffentlichen Schlüssels verifiziert werden.
Token -Schöpfung:
/// create claims valid for 2 hours
let claims = Claims :: create ( Duration :: from_hours ( 2 ) ) ;
let token = key_pair . sign ( claims ) ? ;Token -Überprüfung:
let claims = public_key . verify_token :: < NoCustomClaims > ( & token , None ) ? ;Die verfügbaren Überprüfungsoptionen sind identisch mit denjenigen, die mit symmetrischen Algorithmen verwendet werden.
Ansprüche Objekte unterstützen standardmäßig alle Standardansprüche und können direkt oder über bequeme Helfer festgelegt werden:
let claims = Claims :: create ( Duration :: from_hours ( 2 ) ) .
with_issuer ( "Example issuer" ) . with_subject ( "Example subject" ) ; Antragsdefinierte Ansprüche können jedoch ebenfalls definiert werden. Diese müssen einfach in einem serialisierbaren Typ vorhanden sein (dies erfordert die serde ):
# [ derive ( Serialize , Deserialize ) ]
struct MyAdditionalData {
user_is_admin : bool ,
user_country : String ,
}
let my_additional_data = MyAdditionalData {
user_is_admin : false ,
user_country : "FR" . to_string ( ) ,
} ;Erstellen Sie die Erstellung mit benutzerdefinierten Daten:
let claims = Claims :: with_custom_claims ( my_additional_data , Duration :: from_secs ( 30 ) ) ;Anspruchsurprüfung mit benutzerdefinierten Daten. Beachten Sie das Vorhandensein des benutzerdefinierten Datentyps:
let claims = public_key . verify_token :: < MyAdditionalData > ( & token , None ) ? ;
let user_is_admin = claims . custom . user_is_admin ;Eigenschaften wie die Schlüsselkennung können vor dem Tag oder der Signaturüberprüfung nützlich sein, um den richtigen Schlüssel aus einem Satz herauszuwählen.
let metadata = Token :: decode_metadata ( & token ) ? ;
let key_id = metadata . key_id ( ) ;
let algorithm = metadata . algorithm ( ) ;
// all other standard properties are also accessibleWichtig: Weder die Schlüssel -ID noch der Algorithmus können vertrauen. Dies ist ein unfehlbarer Designfehler des JWT -Standards.
Infolgedessen sollte algorithm nur für Debugging -Zwecke verwendet werden und niemals einen Schlüsseltyp auswählen. In ähnlicher Weise sollte key_id nur verwendet werden, um einen Schlüssel in einem Satz von Schlüssel für denselben Algorithmus auszuwählen.
Zum Minimum muss die Überprüfung unter Verwendung von HS* verboten werden, wenn ursprünglich ein Signaturschema verwendet wurde, um das Token zu erstellen.
Schlüsselkennungen geben den Überprüfern an, welcher öffentliche Schlüssel (oder der gemeinsame Schlüssel) zur Überprüfung verwendet werden sollte. Sie können jederzeit an vorhandene gemeinsame Schlüssel, Schlüsselpaare und öffentliche Schlüssel angeschlossen werden:
let public_key_with_id = public_key . with_key_id ( & "unique key identifier" ) ; Anstatt dies an Anwendungen zu delegieren, kann jwt-simple auch eine solche Kennung für einen vorhandenen Schlüssel erstellen:
let key_id = public_key . create_key_id ( ) ;Dadurch wird eine textkodierte Kennung für den Schlüssel erstellt, ihn angehängt und zurückgibt.
Wenn eine Kennung an einen gemeinsam genutzten Schlüssel oder ein Schlüsselpaar angehängt wurde, werden mit ihnen erstellte Token einbezogen.
jwt-simple enthält Mechanismen zur Minderung der Wiederholungsangriffe:
create_nonce() erstellt und an neue Token angehängt werden. Das Überprüfungsverfahren kann später jedes Token ablehnen, das nicht die erwartete Nonce ( required_nonce Option zur Überprüfung) enthält. Der Entwicklungscode enthält eine cwt -Frachtfunktion, die experimentelle Parsen und Validierung von CWT -Token ermöglicht.
Bitte beachten Sie, dass CWT keine benutzerdefinierten Ansprüche unterstützt. Die erforderlichen Kennungen wurden noch nicht standardisiert.
Auch die vorhandenen Rostkisten für JSON und CBOR -Deserialisierung sind nicht sicher. Eine nicht vertrauenswürdige Partei kann ein serialisiertes Objekt senden, das viel Speicher und CPU benötigt, um sich zu demerialisieren. Für JSON wurden Pflaster hinzugefügt, aber mit dem aktuellen Rost-Werkzeug wäre es schwierig für CBOR.
Als Minderung empfehlen wir dringend, Token abzulehnen, die im Kontext Ihrer Anwendung zu groß sind. Dies kann mit der Option max_token_length -Überprüfung erfolgen.
boring Kiste Als vorübergehende Problemumgehung für Portabilitätsprobleme mit einer der Abhängigkeiten (der boring Kiste) kann diese Bibliothek so kompiliert werden, dass nur Rostimplementierungen verwendet werden.
Um dies zu tun, importieren Sie die Kiste mit default-features=false, features=["pure-rust"] in Ihre Frachtkonfiguration.
Mach es nicht bedingungslos. Dies ist nur für sehr spezifische Setups und Ziele erforderlich und nur bis Probleme mit der boring Kiste gelöst wurden. Die Möglichkeit, dies in Fracht zu konfigurieren, kann sich auch in zukünftigen Versionen ändern.
Statische Aufbauten, die auf die musl -Bibliothek abzielen, erfordern diese Problemumgehung nicht. Verwenden Sie einfach cargo-zigbuild um Ihr Projekt zu erstellen.
Das wasm32-freestanding Ziel (manchmal immer noch als wasm32-unknown-unknown in Rost bezeichnet) wird (wie in "iT Compiles") unterstützt.
Die Verwendung einer nativen JavaScript -Implementierung wird jedoch stattdessen dringend empfohlen. In JavaScript gibt es qualitativ hochwertige JWT-Implementierungen, die die WebCrypto-API nutzen, die bessere Leistung und Sicherheitsgarantien bieten als ein WebAssembly-Modul.
Diese Kiste ist keine Bestätigung von JWT. JWT ist ein schreckliches Design, und eines der vielen Beispiele, dass "aber dies ein Standard ist" bedeutet nicht unbedingt, dass es gut ist.
Ich würde Paseto oder Biscuit stattdessen wärmstens empfehlen, wenn Sie sowohl die Erstellung als auch die Überprüfung der Token kontrollieren.
JWT ist jedoch in der Branche immer noch weit verbreitet und bleibt absolut obligatorisch, um mit beliebten APIs zu kommunizieren.
Diese Kiste wurde ausgelegt:
None Methode aus offensichtlichen Gründen).