في تطبيقات React.js، موضوع الحماية دائمًا من الأمور الحساسة والمهمة، وفي الغالب يكون الأسلوب المستخدم كالتالي:
بعد تسجيل الدخول أو إنشاء مستخدم جديد، نقوم بالحصول على Token ثم نخزنه في الذاكرة المحلية مثل localStorage أو cookies.
لكن للأسف، هذه الطريقة ضعيفة من ناحية الحماية، لأنها معرضة لهجمات مثل XSS (Cross-Site Scripting).
الطريقة الثانية هي حفظ بيانات المستخدم في الذاكرة المؤقتة (in-memory) داخل كائنات React، مما يوفر حماية أكبر لأن البيانات لا تُخزن في المتصفح بشكل دائم، ولكن المشكلة هنا أن هذه البيانات تُفقد بمجرد تحديث الصفحة أو إعادة تحميلها.
الحل الوسط الذي وجدته هو التالي:
في النظم الخلفية (Backend)، ننشئ Token محمي باستخدام httpOnly cookie، بحيث لا يمكن الوصول إليه من جافاسكريبت في المتصفح، مما يقلل خطر هجمات XSS.
السؤال
محمود سعداوي2
السلام عليكم،
في تطبيقات React.js، موضوع الحماية دائمًا من الأمور الحساسة والمهمة، وفي الغالب يكون الأسلوب المستخدم كالتالي:
بعد تسجيل الدخول أو إنشاء مستخدم جديد، نقوم بالحصول على Token ثم نخزنه في الذاكرة المحلية مثل localStorage أو cookies.
لكن للأسف، هذه الطريقة ضعيفة من ناحية الحماية، لأنها معرضة لهجمات مثل XSS (Cross-Site Scripting).
الطريقة الثانية هي حفظ بيانات المستخدم في الذاكرة المؤقتة (in-memory) داخل كائنات React، مما يوفر حماية أكبر لأن البيانات لا تُخزن في المتصفح بشكل دائم، ولكن المشكلة هنا أن هذه البيانات تُفقد بمجرد تحديث الصفحة أو إعادة تحميلها.
الحل الوسط الذي وجدته هو التالي:
في النظم الخلفية (Backend)، ننشئ Token محمي باستخدام httpOnly cookie، بحيث لا يمكن الوصول إليه من جافاسكريبت في المتصفح، مما يقلل خطر هجمات XSS.
مثال على إنشاء Token وتخزينه كـ httpOnly cookie:
const generateToken = (res, userId) => { const token = jwt.sign({ userId }, process.env.JWT_SECRET, { expiresIn: '30d', }); // تعيين الـ JWT كـ httpOnly cookie res.cookie('jwt', token, { httpOnly: true, secure: process.env.NODE_ENV !== 'development', // لتأمين الكوكيز في بيئة الإنتاج sameSite: 'strict', // لمنع هجمات CSRF maxAge: 30 * 24 * 60 * 60 * 1000, // مدة 30 يومًا }); return token; };
ثم ننشئ نقطة نهاية (endpoint) لاسترجاع بيانات المستخدم مع بعض المعلومات الضرورية، مثل:
const getMe = asyncHandler(async (req, res) => { const user = await User.findById(req.user._id).select('-password'); // استرجاع التوكن من الكوكيز const token = req.cookies.jwt; res.json({ _id: user._id, name: user.name, email: user.email, isAdmin: user.isAdmin, token, // نُرسل التوكن أيضاً للواجهة الأمامية }); });
في الواجهة الأمامية، سأستخدم مكتبة tanstack query، التي توفر طريقة مرنة وفعالة للتعامل مع الـ API، مع دعم مدمج للـ caching.
سأقوم بجلب بيانات المستخدم من نقطة النهاية getMe وأحتفظ بها في الذاكرة (in-memory) داخل React. بهذه الطريقة نحقق التوازن بين:
يسعدني جداً سماع آرائكم وملاحظاتكم، فهذه الطريقة نابعة من فكرة محلية، وبالتالي فكل ملاحظة منكم قيمة وستفيدني كثيرًا في تحسين الأمان والأداء.
شكرًا لكم!
2 أجوبة على هذا السؤال
Recommended Posts
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.