HS* JWT) ตัวอย่างRS* , PS* , ES* และ EdDSA อัลกอริทึม) ตัวอย่างboringการใช้งาน JWT (JSON Web Tokens) ใหม่สำหรับการเกิดสนิมที่มุ่งเน้นไปที่ความเรียบง่ายในขณะที่หลีกเลี่ยงข้อผิดพลาดด้านความปลอดภัย 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 จากไลบรารีมาตรฐานสนิม) เนื่องจากแอปพลิเคชันสามารถอนุญาตค่าคืนได้หลายค่า
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" ) ; แต่ยังสามารถกำหนดค่าการเรียกร้องที่กำหนดโดยแอปพลิเคชัน สิ่งเหล่านี้จะต้องมีอยู่ในประเภท serializable (ซึ่งต้องใช้ลัง 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() ขั้นตอนการตรวจสอบสามารถปฏิเสธโทเค็นใด ๆ ที่ไม่รวมตัวเลือก NONCE ที่คาดหวัง (ตัวเลือกการตรวจสอบการตรวจสอบ required_nonce ) รหัสการพัฒนารวมถึงคุณสมบัติการขนส่งสินค้า cwt ที่ช่วยให้สามารถแยกวิเคราะห์และตรวจสอบความถูกต้องของโทเค็น CWT
โปรดทราบว่า CWT ไม่สนับสนุนการเรียกร้องที่กำหนดเอง ตัวระบุที่ต้องการยังไม่ได้มาตรฐาน
นอกจากนี้ลังสนิมที่มีอยู่สำหรับ JSON และ CBOR deserialization ไม่ปลอดภัย บุคคลที่ไม่น่าเชื่อถือสามารถส่งวัตถุที่เป็นอนุกรมที่ต้องใช้หน่วยความจำและซีพียูจำนวนมากเพื่อ deserialize Band-Aids ได้รับการเพิ่มสำหรับ JSON แต่ด้วยเครื่องมือสนิมในปัจจุบันมันจะเป็นเรื่องยากที่จะทำสำหรับ CBOR
ในการบรรเทาเราขอแนะนำให้ปฏิเสธโทเค็นที่จะมีขนาดใหญ่เกินไปในบริบทของแอปพลิเคชันของคุณ ที่สามารถทำได้โดยตัวเลือกการตรวจสอบ max_token_length
boring ในฐานะที่เป็นวิธีแก้ปัญหาชั่วคราวสำหรับปัญหาการพกพาด้วยหนึ่งในการพึ่งพา (ลัง boring ) ไลบรารีนี้สามารถรวบรวมเพื่อใช้การใช้งานสนิมเท่านั้น
ในการทำเช่นนั้นให้นำเข้าลังด้วย default-features=false, features=["pure-rust"] ในการกำหนดค่าสินค้าของคุณ
อย่าทำอย่างไม่มีเงื่อนไข สิ่งนี้จำเป็นสำหรับการตั้งค่าและเป้าหมายที่เฉพาะเจาะจงมากเท่านั้นและจนกว่าจะมีปัญหาเกี่ยวกับลัง boring ได้รับการแก้ไข วิธีการกำหนดค่าสิ่งนี้ในสินค้าอาจเปลี่ยนแปลงในรุ่นอนาคต
การสร้างแบบสแตติกที่กำหนดเป้าหมายไปที่ห้องสมุด musl ไม่ต้องการวิธีแก้ปัญหานั้น เพียงแค่ใช้ cargo-zigbuild เพื่อสร้างโครงการของคุณ
เป้าหมาย wasm32-freestanding (บางครั้งก็เรียกว่า wasm32-unknown-unknown ใน Rust) ได้รับการสนับสนุน (เช่นใน "IT Compiles")
อย่างไรก็ตามการใช้การใช้งาน JavaScript ดั้งเดิมแนะนำแทน มีการใช้งาน JWT ที่มีคุณภาพสูงใน JavaScript ใช้ประโยชน์จาก WebCrypto API ที่ให้ประสิทธิภาพและการรับประกันความปลอดภัยที่ดีกว่าโมดูล WebAssembly
ลังนี้ไม่ใช่การรับรอง JWT JWT เป็นการออกแบบที่น่ากลัวและหนึ่งในตัวอย่างมากมายที่ "แต่นี่เป็นมาตรฐาน" ไม่ได้หมายความว่ามันดี
ฉันขอแนะนำ Paseto หรือ Biscuit แทนหากคุณควบคุมทั้งการสร้างโทเค็นและการตรวจสอบ
อย่างไรก็ตาม JWT ยังคงใช้กันอย่างแพร่หลายในอุตสาหกรรมและยังคงจำเป็นอย่างยิ่งในการสื่อสารกับ API ยอดนิยม
ลังนี้ถูกออกแบบมาเพื่อ:
None ลายเซ็นด้วยเหตุผลที่ชัดเจน)