HS* JWT) مثالRS* ، PS* ، ES* و EdDSA )boringيركز تطبيق JWT (JWTN Web الرموز "الجديدة على الصدأ الذي يركز على البساطة ، مع تجنب عيوب أمان JWT الشائعة.
jwt-simple غير مصقول ويدعم جميع خوارزميات المصادقة والتوقيع التي تم نشرها بشكل شائع:
| اسم خوارزمية JWT | وصف |
|---|---|
HS256 | HMAC-SHA-256 |
HS384 | HMAC-SHA-384 |
HS512 | HMAC-SHA-512 |
BLAKE2B | Blake2B-256 |
RS256 | RSA مع PKCS#1V1.5 حشو / SHA-256 |
RS384 | RSA مع PKCS#1V1.5 حشو / SHA-384 |
RS512 | RSA مع PKCS#1V1.5 حشو / 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 ( ) ; يمكن تصدير المفتاح على أنه BYTES باستخدام 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 Standard) ، لأن التطبيق يمكن أن يسمح قيم الإرجاع المتعددة.
RS* ، PS* ، ES* و EdDSA )يتطلب التوقيع زوجًا مفتاحًا: مفتاح سري يستخدم لإنشاء الرموز ، ومفتاح عام ، يمكنه التحقق منها فقط.
استخدم دائمًا مخطط التوقيع إذا لم يثق كلا الطرفين في النهاية ببعضهما البعض ، مثل الرموز المبادلة بين العملاء ومقدمي واجهة برمجة التطبيقات.
الخلق الرئيسي:
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 تتيح التحليل التجريبي والتحقق من رموز CWT.
يرجى ملاحظة أن CWT لا يدعم المطالبات المخصصة. لم يتم توحيد المعرفات المطلوبة بعد.
أيضا ، فإن صناديق الصدأ الحالية لـ JSON و CBOR غير آمنة. يمكن للطرف غير الموثوق أن يرسل كائنًا متسلسلًا يتطلب الكثير من الذاكرة ووحدة المعالجة المركزية لإلغاء التسلل. تمت إضافة Band-Aids لـ JSON ، ولكن مع أدوات الصدأ الحالية ، سيكون من الصعب القيام به لـ CBOR.
كتخفيف ، نوصي بشدة برفض الرموز التي ستكون كبيرة جدًا في سياق تطبيقك. يمكن القيام بذلك باستخدام خيار التحقق من max_token_length .
boring باعتبارها حلًا مؤقتًا لمشكلات قابلية النقل مع أحد التبعيات (الصندوق boring ) ، يمكن تجميع هذه المكتبة لاستخدام تطبيقات الصدأ فقط.
من أجل القيام بذلك ، استيراد الصندوق مع default-features=false, features=["pure-rust"] في تكوين الشحن الخاص بك.
لا تفعل ذلك دون قيد أو شرط. هذا مطلوب فقط لإعدادات وأهداف محددة للغاية ، وفقط حتى يتم حل المشكلات مع الصندوق boring . قد تتغير طريقة تكوين هذا في البضائع أيضًا في الإصدارات المستقبلية.
لا يتطلب بناء مكتبة musl . فقط استخدم cargo-zigbuild لبناء مشروعك.
يتم دعم هدف wasm32-freestanding (الذي لا يزال يسمى أحيانًا wasm32-unknown-unknown في الصدأ) (كما في "IT").
ومع ذلك ، يوصى بشدة باستخدام تطبيق JavaScript الأصلي بدلاً من ذلك. هناك تطبيقات JWT عالية الجودة في JavaScript ، وتستفيد من واجهة برمجة تطبيقات WebCrypto ، والتي توفر ضمانات أفضل للأداء والأمان من وحدة التجميع على شبكة الإنترنت.
هذا الصندوق ليس تأييد JWT. JWT هو تصميم فظيع ، وأحد الأمثلة العديدة التي "ولكن هذا معيار" لا يعني بالضرورة أنه جيد.
أود أن أوصي بشدة Paseto أو Biscuit بدلاً من ذلك إذا كنت تتحكم في كل من إنشاء الرمز المميز والتحقق منه.
ومع ذلك ، لا يزال JWT يستخدم على نطاق واسع في هذه الصناعة ، ولا يزال إلزاميًا تمامًا للتواصل مع واجهات برمجة التطبيقات الشعبية.
تم تصميم هذا الصندوق إلى:
None لأسباب واضحة).