HS* JWT -алгоритмы) примерRS* , PS* , ES* и EdDSA algorithms) примерboring ящикомНовая реализация JWT (JSON Web Tokens) для Rust, которая фокусируется на простоте, избегая при этом общих ловушек безопасности JWT.
jwt-simple неопинирован и поддерживает все обычно развернутые алгоритмы аутентификации и подписи:
| JWT Алгоритм название | Описание |
|---|---|
HS256 | HMAC-SHA-256 |
HS384 | HMAC-SHA-384 |
HS512 | HMAC-SHA-512 |
BLAKE2B | Blake2b-256 |
RS256 | RSA с PKCS#1V1.5 Padding / SHA-256 |
RS384 | RSA с PKCS#1V1.5 Padding / SHA-384 |
RS512 | RSA с PKCS#1V1.5 Padding / SHA-512 |
PS256 | RSA с PSS Padding / Sha-256 |
PS384 | RSA с PSS Padding / SHA-384 |
PS512 | RSA с PSS Padding / SHA-512 |
ES256 | ECDSA над P256 / SHA-256 |
ES384 | ECDSA над P384 / SHA-384 |
ES256K | ECDSA над SECP256K1 / SHA-256 |
EdDSA | ED25519 |
jwt-simple может быть составлен из коробки в Webassembly/wasi. Он полностью совместим с быстрым вычислением .
ВАЖНО: Цель JWT состоит в том, чтобы убедиться, что данные были созданы стороной, знающей секретный ключ. Он не обеспечивает никакой конфиденциальности: данные JWT просто закодированы как Base64 и не зашифрованы.
cargo.toml :
[ dependencies ]
jwt-simple = " 0.12 "Ржавчина:
use jwt_simple :: prelude :: * ; Ошибки возвращаются как jwt_simple::Error (псевдоним для типа Error ящика thiserror ираза).
HS* JWT -алгоритмы) примерСхемы аутентификации используют тот же ключ для создания и проверки токенов. Другими словами, обе стороны должны в конечном итоге доверять друг другу, иначе проверка также может создать произвольные токены.
Ключевое создание:
use jwt_simple :: prelude :: * ;
// create a new key for the `HS256` JWT algorithm
let key = HS256Key :: generate ( ) ; Ключ можно экспортировать как байты с помощью key.to_bytes() и восстановить с помощью HS256Key::from_bytes() .
Создание токена:
/// create claims valid for 2 hours
let claims = Claims :: create ( Duration :: from_hours ( 2 ) ) ;
let token = key . authenticate ( claims ) ? ;-> Сделано!
let claims = key . verify_token :: < NoCustomClaims > ( & token , None ) ? ;-> Сделано! Не требуется дополнительных шагов.
Срок действия ключа, время начала, теги аутентификации и т. Д. Проверяется автоматически. Функция не выполняется с JWTError::InvalidAuthenticationTag если тег аутентификации недействителен для данного ключа.
Полный набор претензий может быть проверен в объекте claims , если это необходимо. NoCustomClaims означает, что приложением также можно поддерживать только стандартный набор претензий, но также могут быть поддержаны требования, определяемые приложением.
Дополнительные шаги проверки могут быть включены с помощью структуры ValidationOptions :
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 ) ) ? ; Обратите внимание, что allowed_issuers и allowed_audiences не являются строками, а наборами строк (используя тип HashSet из стандартной библиотеки Rust), поскольку приложение может разрешить несколько возвратных значений.
RS* , PS* , ES* и EdDSA algorithms) примерПодпись требует пары ключей: секретный ключ, используемый для создания токенов, и открытый ключ, который может их проверить.
Всегда используйте схему подписи, если обе стороны в конечном итоге не доверяют друг другу, например, токены, обменяемые между клиентами и поставщиками API.
Ключевое создание:
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 ( ) ;Ключи могут быть экспортированы в виде байтов для последующего повторного использования, и импортируются с байтов или, для RSA, из отдельных параметров, DER-кодированных данных или данных, кодируемых PEM.
Создание пары клавиш RSA, используя OpenSSL и PEM -импорт секретного ключа:
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 ) ? ; Создание и проверка токена работают так же, как и в алгоритмах HS* , за исключением того, что токены создаются с помощью пары ключей и проверяются с использованием соответствующего открытого ключа.
Создание токена:
/// create claims valid for 2 hours
let claims = Claims :: create ( Duration :: from_hours ( 2 ) ) ;
let token = key_pair . sign ( claims ) ? ;Проверка токена:
let claims = public_key . verify_token :: < NoCustomClaims > ( & token , None ) ? ;Доступные варианты проверки идентичны тем, которые используются с симметричными алгоритмами.
Объекты претензий поддерживают все стандартные претензии по умолчанию, и они могут быть установлены напрямую или через удобные помощники:
let claims = Claims :: create ( Duration :: from_hours ( 2 ) ) .
with_issuer ( "Example issuer" ) . with_subject ( "Example subject" ) ; Но также могут быть определены претензии, определяемые приложением. Они просто должны присутствовать в сериализуемом типе (это требует 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 ( ) ,
} ;Создание претензий с помощью пользовательских данных:
let claims = Claims :: with_custom_claims ( my_additional_data , Duration :: from_secs ( 30 ) ) ;Проверка претензий с помощью пользовательских данных. Обратите внимание на наличие пользовательского типа данных:
let claims = public_key . verify_token :: < MyAdditionalData > ( & token , None ) ? ;
let user_is_admin = claims . custom . user_is_admin ;Свойства, такие как идентификатор ключа, могут быть полезны до проверки тега или подписи, чтобы выбрать правильный ключ из набора.
let metadata = Token :: decode_metadata ( & token ) ? ;
let key_id = metadata . key_id ( ) ;
let algorithm = metadata . algorithm ( ) ;
// all other standard properties are also accessibleВажно: ни ключевой идентификатор, ни алгоритм не могут быть доверяют. Это нефиксируемый недостаток дизайна стандарта JWT.
В результате algorithm следует использовать только для отладки, и никогда не выбирать тип ключа. Точно так же key_id следует использовать только для выбора клавиши в наборе ключей, сделанных для того же алгоритма.
При минимуме, проверка с использованием HS* должна быть запрещена, если схема подписи была первоначально использована для создания токена.
Идентификаторы ключей указывают на проверку, какой открытый ключ (или общий ключ) должен использоваться для проверки. Они могут быть прикреплены в любое время к существующим общим ключам, парам ключей и публичным ключам:
let public_key_with_id = public_key . with_key_id ( & "unique key identifier" ) ; Вместо того, чтобы делегировать это в приложения, jwt-simple также может создать такой идентификатор для существующего ключа:
let key_id = public_key . create_key_id ( ) ;Это создает текстовый идентификатор для ключа, прикрепляет его и возвращает его.
Если идентификатор был прикреплен к общему ключу или паре ключей, токены, созданные с ними, будут включать его.
jwt-simple включает механизмы для смягчения атак на воспроизведение:
create_nonce() . Процедура проверки может впоследствии отклонить любой токен, который не включает ожидаемый nonce (опция проверки required_nonce ). Код разработки включает в себя функцию cwt Cargo, которая обеспечивает экспериментальный анализ и проверку токенов CWT.
Обратите внимание, что CWT не поддерживает пользовательские претензии. Требуемые идентификаторы еще не были стандартизированы.
Кроме того, существующие ящики ржавчины для JSON и Cbor Deserialization не являются безопасными. Недоверенная сторона может отправить сериализованный объект, который требует большой памяти и процессора для десериализации. Оплачиваемые группы были добавлены для JSON, но с текущим инструментом ржавчины это было бы сложно сделать для CBOR.
В качестве смягчения мы настоятельно рекомендуем отклонить токены, которые были бы слишком большими в контексте вашего приложения. Это может быть сделано с помощью опции проверки max_token_length .
boring ящиком В качестве временного обходного пути для проблем портативности с одной из зависимостей ( boring ящик), эта библиотека может быть составлена для использования только реализаций ржавчины.
Для этого импортируйте ящик с default-features=false, features=["pure-rust"] в конфигурации вашего груза.
Не делайте это безоговорочно. Это требуется только для очень специфических настроек и целей, и только до тех пор, пока не будут решены проблемы со boring ящиком. Способ настроить это в грузе также может измениться в будущих версиях.
Статические сборки, нацеленные на musl библиотеку, не требуют этого обходного пути. Просто используйте cargo-zigbuild чтобы построить свой проект.
wasm32-freestanding (все еще иногда называемая wasm32-unknown-unknown in rust) поддерживается (как в «It Specileds»).
Однако вместо этого рекомендуется использование нативной реализации JavaScript. В JavaScript существуют высококачественные реализации JWT, использующие API WebCrypto, которые обеспечивают лучшие гарантии производительности и безопасности, чем модуль Webassembly.
Этот ящик не является одобрением JWT. JWT - ужасный дизайн, и один из многих примеров, которые «но это стандарт», не обязательно означает, что это хорошо.
Я очень рекомендую Paseto или Biscuit, если вы контролируете как создание токенов, так и проверку.
Тем не менее, JWT по -прежнему широко используется в отрасли и остается абсолютно обязательным для общения с популярными API.
Этот ящик был разработан:
None Signature по очевидным причинам).