
مستودع تعليمي يوضح أنماط العرض في Next.js (CSR, RSC, SSG, ISR, SSR) ومختبر عملي لاستغلال SSRF لـ CVE-2024-34351 مع خطوات التخفيف.
يمكن استخدام هذا المستودع كدعم لتقديم لقاء أو أكثر. المسار هو كما يلي...
يعتمد هذا العمل بشكل أساسي على مصدرين:
1-csr-load-data vanilla react SPA loading data[!IMPORTANT] CSR (Client-Side Rendering): يتم تسليم كود React إلى المتصفح، الذي يقوم بإنشاء المحتوى الذي يتم إدراجه في DOM.

cd 1-csr-load-data
npm start

2-csr-router vanilla react SPA routing[!IMPORTANT] بعد تحميل الصفحة لأول مرة، يستخدم التنقل إلى صفحات أخرى على نفس موقع الويب JavaScript لإعادة عرض أجزاء من الصفحة دون الحاجة إلى تحديث كامل للصفحة.
cd 2-csr-router
npm start

3-rsc-load-data React Server Components (Next.js impl) loading data[!IMPORTANT] مكونات React التي تمت كتابتها ليتم تشغيلها فقط على الخادم، وليس في المتصفح.

cd 3-rsc-load-data
npm run build
npm run start

4-rsc-router React Server Components (Next.js impl) routing[!IMPORTANT] يتم تنفيذ المكونات فقط على الخادم. السلوك الافتراضي هو التقديم الثابت: يتم تنفيذ المكونات في وقت البناء.
cd 4-rsc-router
npm run build
npm run start

5-SSR SSR Server Side Rendering[!IMPORTANT] يعني SSR تقديم مكونات العميل مسبقًا على الخادم. يتم تشغيل كود React في الوقت الذي يتم طلبه. قد يتم تخزين النتيجة مؤقتًا للطلبات المستقبلية.
أفضل ممارسة: تعريف مكونات 'use client'; في أدنى مستوى ممكن في شجرة المكونات.
[!IMPORTANT] "في React، "hydration" هي كيفية "ربط" React بـ HTML الموجود الذي تم تقديمه بالفعل بواسطة React في بيئة خادم. أثناء hydration، سيحاول React إرفاق مستمعي الأحداث بالعلامات الموجودة وتولي تقديم التطبيق على العميل. في التطبيقات المبنية بالكامل مع React، عادةً ما تقوم بـ "hydration" لجذر واحد فقط، مرة واحدة عند بدء التشغيل للتطبيق بأكمله."
https://react.dev/reference/react-dom/client/hydrateRoot
https://www.gatsbyjs.com/docs/conceptual/partial-hydration/
cd 5-ssr
npm run build
npm run start

6-pages-router-ssg (Next.js impl)[!IMPORTANT] SSG (Static Site Generation) باستخدام موجه الصفحات: يتم تشغيل كود React عند بناء تطبيقك، ويكون الناتج المُنشأ ثابتًا.
cd 6-pages-router-ssg
npm run build
npm run start
7-pages-router-isr (Next.js impl)[!IMPORTANT] ISR (باستخدام موجه الصفحات): "يسمح لك Next.js بإنشاء أو تحديث صفحات ثابتة بعد بناء موقعك. يمكنك Incremental Static Regeneration (ISR) من استخدام التوليد الثابت على أساس كل صفحة، دون الحاجة إلى إعادة بناء الموقع بأكمله. مع ISR، يمكنك الاحتفاظ بفوائد الثبات مع التوسع إلى ملايين الصفحات."
cd 7-pages-router-isr
npm run build
npm run start
"قد تصبح البيانات قديمة عند وقت الطلب"
https://vercel.com/blog/nextjs-server-side-rendering-vs-static-generation
https://react.dev/reference/rsc/server-actions
...
8-ssrf-14.1.0https://www.assetnote.io/resources/research/digging-for-ssrf-in-nextjs-apps
14.1.1redirect(/blog/${inputValue});المصدر: https://www.assetnote.io/resources/research/digging-for-ssrf-in-nextjs-apps
Next.JS ينفذ الطلب من جانب الخادم، ثم يعيد النتيجة إلى المتصفح:
redirect('/blog/123'); تبني URL http://207.154.209.99/blog/123.
لبناء هذا URL، يحصل Next.JS على host 207.154.209.99 من header HTTP للطلب الأصلي.Content-Type: text/x-component، فإن Next.JS يستعلم URL باستخدام HTTP GET.للوصول إلى SSRF على الخادم المستهدف، يجب تنفيذ خادم آخر:
Content-Type: text/x-component، لأي طلب HEAD
8-ssrf-14.1.0في /etc/nginx/sites-available/nextjs
قبل:
server {
listen 80 default_server;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
بعد:
server {
listen 80;
server_name 207.154.209.99;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host 207.154.209.99;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
خطر وجود تأثيرات جانبية...
https://nginxtutorials.com/nginx-proxy_set_header-directive/
https://github.com/vercel/next.js/security/advisories/GHSA-fr5h-rqp8-mj6g

الصفحات في دليل app هي Server Components بشكل افتراضي. هذا يختلف عن دليل pages حيث تكون الصفحات Client Components.
الترقية إلى Next.js 13 لا تتطلب استخدام App Router الجديد. يمكنك الاستمرار في استخدام pages مع ميزات جديدة تعمل في كلا الدليلين.
إذا أردنا مقارنة أداء التحميل للحلول المختلفة، يمكننا إضافة metrics web core vital في console.log.
https://web.dev/articles/fcp?hl=fr
https://rsc-parser.vercel.app/
https://github.com/reactjs/rfcs/blob/main/text/0188-server-components.md#does-this-replace-ssr
https://www.youtube.com/watch?v=jEJEFAc8tSI
ISR باستخدام App router؟
في Next.js App Router، جميع البيانات التي تم جلبها تصبح الآن ثابتة بشكل افتراضي، وتُقدَّم في وقت البناء. ومع ذلك، يمكن تغيير ذلك بسهولة: يوسع Next.js كائن خيارات fetch لتوفير مرونة في قواعد التخزين المؤقت وإعادة التحقق. يمكنك استخدام الخيار {next: {revalidate: number}} لتحديث البيانات الثابتة على فترات زمنية محددة أو عند حدوث تغييرات في الخلفية (Incremental Static Regeneration)، بينما يمكن تمرير الخيار {cache: 'no-store'} في طلب fetch للبيانات الديناميكية (server-side rendering).
https://www.telerik.com/blogs/current-state-react-server-components-guide-perplexed
https://github.com/reactjs/server-components-demo
https://dev.to/vteacher/let-s-make-a-web-application-with-react-server-components-5dmg
https://react.dev/blog/2024/04/25/react-19
https://react.dev/reference/rsc/server-components
https://www.youtube.com/watch?v=ePAPd9qzGyM
https://www.joshwcomeau.com/react/server-components/
https://nextjs.org/docs/pages/building-your-application/rendering/static-site-generation
https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-props
https://react.dev/reference/rsc/server-components#server-components-without-a-server