HS* JWT算法)示例RS* , PS* , ES*和EdDSA算法)示例boring板條箱圍繞編譯問題進行工作RUST的新的JWT(JSON Web令牌)實現,重點是簡單,同時避免了常見的JWT安全性陷阱。
jwt-simple未經封閉,並支持所有通常部署的身份驗證和簽名算法:
| JWT算法名稱 | 描述 |
|---|---|
HS256 | HMAC-SHA-256 |
HS384 | HMAC-SHA-384 |
HS512 | HMAC-SHA-512 |
BLAKE2B | Blake2B-256 |
RS256 | 帶有PKCS#1V1.5填充 / SHA-256的RSA |
RS384 | 帶有PKCS#1V1.5填充 / SHA-384的RSA |
RS512 | 帶PKCS#1V1.5填充 / SHA-512的RSA |
PS256 | 帶PSS填充 / SHA-256的RSA |
PS384 | 帶PSS填充 / SHA-384的RSA |
PS512 | 帶PSS填充 / SHA-512的RSA |
ES256 | ECDSA超過P256 / SHA-256 |
ES384 | p384 / sha-384的ECDSA |
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值( thiserror Crate的Error類型的別名)返回。
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不是字符串,而是字符串集(使用Rust Standard庫中的HashSet類型),因為該應用程序可以允許多個返回值。
RS* , PS* , ES*和EdDSA算法)示例簽名需要一個鑰匙對:用於創建令牌和公共密鑰的秘密密鑰,只能驗證它們。
如果雙方最終不相互信任,例如客戶和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重要的是:關鍵ID和算法都無法信任。這是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()索賠功能創建Nonces並將其附加到新令牌上。驗證過程稍後可以拒絕任何不包括預期nonce的令牌( required_nonce驗證選項)。開發代碼包括cwt貨物功能,該功能可以實現CWT代幣的實驗解析和驗證。
請注意,CWT不支持自定義索賠。所需的標識符尚未標準化。
同樣,現有的JSON和CBOR避難所的生鏽板條也不安全。一個不信任的一方可以發送一個需要大量內存和CPU的序列化對象。 JSON添加了創可貼,但是使用當前的生鏽工具,對於CBOR來說,這將是棘手的。
作為緩解措施,我們強烈建議您拒絕在您的應用程序中太大的代幣。可以通過max_token_length驗證選項來完成。
boring板條箱圍繞編譯問題進行工作作為一個依賴關係之一( boring板條箱)的臨時解決方法,可以編譯該庫以僅使用Rust實現。
為了這樣做,請在貨物配置中導入具有default-features=false, features=["pure-rust"] 。
不要無條件地這樣做。這僅對於非常特定的設置和目標需要,並且只有在解決了boring箱子問題之前。在貨物中配置此設置的方法也可能會在以後的版本中改變。
針對musl庫的靜態構建不需要解決方法。只需使用cargo-zigbuild來構建您的項目即可。
支持wasm32-freestanding目標(有時仍稱為Rust中的wasm32-unknown-unknown )(如“ IT Compiles”)。
但是,強烈建議使用本機JavaScript實現。 JavaScript中有高質量的JWT實現,利用WebCrypto API,比WebAssembly模塊提供了更好的性能和安全保證。
這個板條箱不是JWT的認可。 JWT是一種可怕的設計,也是“但這是標準”的眾多示例之一,並不一定意味著它是好的。
如果您控制令牌創建和驗證,我強烈建議您推薦帕斯託或餅乾。
但是,JWT仍在行業中廣泛使用,並且與流行的API溝通絕對是必不可少的。
該板條箱的設計為:
None簽名方法外)。