لماذا Rust هو الخيار الأمثل للمصادقة؟
\n\nإذا كنت تكتب تطبيق ويب باستخدام Rust، فأنت بالفعل متقدم خطوة واحدة في مجال الأمان. Rust لا يتسامح مع أخطاء الذاكرة، مما يعني أن العديد من نقاط الضعف (تجاوز سعة المخزن المؤقت، use-after-free) يتم استبعادها في مرحلة التجميع. لكن المترجم لن يحميك من منطق المصادقة السيئ. هذا هو موضوعنا - كيفية بناء مصادقة آمنة في Rust باستخدام الممارسات الحديثة.
\n\nفي هذه المقالة، سنقوم بتجميع وحدة مصادقة كاملة: تجزئة كلمات المرور باستخدام bcrypt، وإصدار رموز JWT، والتحقق عبر middleware في Actix-web، والحماية من الهجمات النموذجية. الكود سيكون عمليًا - يمكنك استخدامه بثقة في مشروعك.
1. تجزئة كلمات المرور: لماذا bcrypt وليس SHA-256؟
\n\nيعتقد العديد من المبتدئين: "سأستخدم SHA-256، إنه سريع وموثوق". وهذا خطأ فادح. SHA هي دالة تجزئة تشفيرية، لكنها سريعة جدًا. يمكن للمهاجم تجربة مليارات التركيبات في الثانية. نحتاج إلى دالة بطيئة، مصممة خصيصًا لكلمات المرور.
\n\nbcrypt هو المعيار الذهبي. يتضمن "ملح" (salt) و"عامل التكلفة" (cost factor) الذي يمكن زيادته مع تزايد القوة الحاسوبية.
\n\nإضافة bcrypt إلى Cargo.toml
\n[dependencies]\nbcrypt = "0.15"\n\nتجزئة كلمة المرور
\nuse bcrypt::{hash, verify, DEFAULT_COST};\n\nfn hash_password(plain: &str) -> Result<String, bcrypt::BcryptError> {\n hash(plain, DEFAULT_COST) // cost = 12 (افتراضيًا)\n}\n\nfn verify_password(plain: &str, hashed: &str) -> bool {\n verify(plain, hashed).unwrap_or(false)\n}\n\nلاحظ: verify يستخرج الملح من التجزئة بنفسه. لست بحاجة لتخزين الملح بشكل منفصل - فهو موجود بالفعل داخل سلسلة التجزئة. هذا آمن ومريح.
2. رموز JWT: كيف لا تفشل في المصادقة
\n\nبعد أن يدخل المستخدم كلمة المرور، يجب أن نصدر له "تصريح مرور". JWT (JSON Web Token) هو تنسيق مضغوط ومكتفي بذاته. لكن الشيطان يكمن في التفاصيل:
\n\n- \n
- لا تخزن المفتاح السري في الكود. استخدم متغيرات البيئة. \n
- حدد عمرًا قصيرًا. رمز الوصول (Access token) - 15-30 دقيقة، رمز التحديث (Refresh token) - 7-30 يومًا. \n
- لا تضع بيانات حساسة في الحمولة (payload). فقط معرف المستخدم والدور. \n
تنفيذ JWT باستخدام jsonwebtoken
\n\nuse jsonwebtoken::{encode, decode, Header, Validation, EncodingKey, DecodingKey};\nuse serde::{Serialize, Deserialize};\nuse chrono::{Utc, Duration};\n\n#[derive(Debug, Serialize, Deserialize)]\npub struct Claims {\n pub sub: String, // معرف المستخدم\n pub exp: usize, // طابع زمني لانتهاء الصلاحية\n pub iat: usize, // طابع زمني للإصدار\n}\n\npub fn create_token(user_id: &str, secret: &str) -> Result<String, jsonwebtoken::errors::Error> {\n let now = Utc::now();\n let claims = Claims {\n sub: user_id.to_owned(),\n exp: (now + Duration::minutes(30)).timestamp() as usize,\n iat: now.timestamp() as usize,\n };\n encode(&Header::default(), &claims, &EncodingKey::from_secret(secret.as_bytes()))\n}\n\npub fn validate_token(token: &str, secret: &str) -> Result<Claims, jsonwebtoken::errors::Error> {\n let token_data = decode::<Claims>(\n token,\n &DecodingKey::from_secret(secret.as_bytes()),\n &Validation::default(),\n )?;\n Ok(token_data.claims)\n}\n\n3. تجميع كل شيء معًا: Actix-web + middleware
\n\nالآن سنربط التجزئة و JWT في تطبيق ويب كامل باستخدام Actix-web. سنكتب middleware للتحقق من الرمز في كل طلب محمي.
\n\nهيكل المشروع
\nsrc/\n├── main.rs\n├── auth.rs # التجزئة، JWT\n├── middleware.rs # التحقق من الرمز\n└── handlers.rs #