رفتن به محتوا

Nuxt 4.6.3: پنج هشدار امنیتی، بیشتر روی dev server و route rules

۷ دقیقه مطالعه
nuxt
nitro
security

نسخه v4.6.3 از Nuxt امروز، ۲۷ اکتبر، منتشر شد. یادداشت‌های انتشار آن را یک patch release معرفی می‌کنند، اما فهرست تغییرات با پنج هشدار امنیتی شروع می‌شود و بعد فهرست بلندی از رفع اشکال در route ruleها و ناوبری می‌آید. این یادداشت‌ها شدت، امتیاز CVSS یا بازهٔ نسخه‌های آسیب‌پذیر را نمی‌دهند؛ برای آن‌ها باید به صفحهٔ هر GHSA سر بزنید. آنچه در ادامه می‌خوانید همان چیزی است که صفحهٔ انتشار می‌گوید و معنایش برای یک اپلیکیشن production.

پنج هشدار امنیتی

یادداشت‌های انتشار فقط عنوان‌های یک‌خطی می‌دهند. برداشت من از هرکدام:

هشداربخشرفع چه می‌کند
GHSA-x287-wcfc-q46cviteجلوی خواندن فایل‌هایی که در گزارش خطای کلاینت نام برده شده‌اند را می‌گیرد
GHSA-648h-gw55-m2g7viteدسترسی dev server به خروجی dev مربوط به Nitro را می‌بندد
GHSA-3xf4-9g3c-4h4wvitedev server دیگر app secret تولیدشده را سرو نمی‌کند
GHSA-9v7c-q64q-vv33nitro, nuxtdot segmentها (. و ..) را در مسیر درخواست درست مدیریت می‌کند
GHSA-2fxj-c3j7-rr69nuxtredirect route ruleها را روی page islandها اعمال می‌کند

سه مورد از این پنج مورد در یکپارچه‌سازی Vite هستند و به dev server مربوط‌اند. این موضوع میزان مواجهه را مشخص می‌کند: اگر nuxt dev را فقط روی localhost اجرا می‌کنید، این موارد کمتر از آنچه به نظر می‌رسد نگران‌کننده‌اند. اهمیتشان وقتی است که dev server از بیرون در دسترس باشد؛ مثلاً داخل کانتینر با پورت منتشرشده، روی شبکهٔ مشترک، یا پشت تونلی که برای دمو استفاده می‌شود.

مورد app secret به‌خاطر 4.6.0 توجه بیشتری می‌خواهد. طبق فهرست انتشارها، آن نسخه یک secret ریشه برای اپلیکیشن معرفی کرد که با NUXT_APP_SECRET تنظیم می‌شود و برای پشتیبانی جدید از session استفاده می‌شود. dev serverی که بشود آن را وادار به سرو کردن secret تولیدشده کرد، دقیقاً چیزی است که «فقط dev است» را به نشت واقعی credential تبدیل می‌کند. صفحهٔ انتشار نمی‌گوید این مورد در عمل قابل بهره‌برداری بوده یا نه و من هم حدس نمی‌زنم. اگر روی 4.6.x یک dev server را در معرض کلاینت‌های نامعتمد گذاشته‌اید، هر secretی را که از secret تولیدشده مشتق یا کنار آن ذخیره شده بچرخانید.

dot segment در مسیر درخواست

هشدار چهارم هم Nitro و هم Nuxt را در بر می‌گیرد: dot segmentها در مسیر درخواست اکنون درست مدیریت می‌شوند. dot segmentها همان بخش‌های /./ و /../ در مسیرند. هر چیزی که مسیر را پیش از نرمال‌سازی با یک rule، پیشوند یا پوشهٔ استاتیک تطبیق دهد، می‌تواند با لایه‌ای که در نهایت فایل را resolve می‌کند اختلاف پیدا کند. جزئیات در خود advisory است نه صفحهٔ انتشار؛ نکتهٔ عملی این است که route ruleها و middlewareهایی که از پیشوند مسیر محافظت می‌کنند فقط به اندازهٔ نرمال‌سازی‌ای ایمن‌اند که پیش از اجرایشان انجام می‌شود.

redirect ruleها روی page islandها

redirect route ruleها اکنون روی page islandها اعمال می‌شوند. یک redirect در routeRules این شکل را دارد:

ts
// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    "/old-pricing": { redirect: { to: "/pricing", statusCode: 301 } },
  },
});

طبق برداشت من از عنوان advisory، پیش از رفع، درخواست به شکل island یک صفحه می‌توانست redirectی را که درخواست عادی صفحه می‌خورد دور بزند. اگر از redirect برای بازنشسته کردن صفحه‌هایی استفاده می‌کنید که دیگر نباید رندر شوند، این همان موردی است که باید دوباره تست کنید: endpoint مربوط به island چنین صفحه‌ای را درخواست کنید و مطمئن شوید redirect می‌گیرید، نه محتوای رندرشده. این ادامهٔ سخت‌سازی server islandها در 4.6.2 و انتشار امنیتی 4.5.1 است که طبق فهرست انتشارها چند مشکل island و مجوزدهی route rule را رفع کرد.

تغییر رفتار route ruleها که باید تست کنید

جدا از هشدارها، مجموعه‌ای از رفع‌ها نحوهٔ تطبیق کلیدهای route rule را تغییر می‌دهد. هر مورد یک خط است؛ برای هرچه به آن وابسته‌اید PRها را بخوانید:

  • route ruleهای دارای constraint دیگر مسیرهای پویا را پوشش‌دادهشده فرض نمی‌کنند (#36701).
  • مسیر صفحه پیش از تطبیق با کلید route rule انکد می‌شود (#36683).
  • پیشوند صفحه هنگام یافتن استثناهای route rule نرمال می‌شود (#36685).
  • وقتی sensitive: false است، constraintهای وابسته به حروف بزرگ و کوچک رد می‌شوند (#36708).
  • constraintهای regex در کلیدهای route rule دیگر case-fold نمی‌شوند (#36694).
  • الگوهای wildcard مربوط به noScripts در Nitro تک‌segment می‌مانند.

محور کار با تطبیق غیرحساس به حروف در 4.6.2 هماهنگ است: تطبیق rule با آنچه router resolve می‌کند یکی شود. اثر جانبی‌اش این است که ruleی که اتفاقی چیزی را پوشش می‌داد حالا شاید نکند، و ruleی که محدود نوشته بودید ممکن است متفاوت رفتار کند. اگر هدرهای امنیتی یا کش no-store را در routeRules نگه می‌دارید، یک اسکریپت کوچک بنویسید که URLهای نماینده (حروف مختلط، کاراکترهای انکدشده، پارامترهای پویا) را درخواست کند و هدرها را بسنجد:

bash
for p in /admin/x /Admin/x /admin/%78 /admin/../admin/x; do
  printf '%s -> ' "$p"
  curl -s -o /dev/null -D - --path-as-is "http://localhost:3000$p" | grep -i '^cache-control' || echo "(none)"
done

این smoke test خود من است و در یادداشت‌های انتشار نیست. گزینهٔ --path-as-is جلوی این را می‌گیرد که curl خودش dot segmentها را جمع کند، که هنگام آزمودن رفع بالا همان چیزی است که می‌خواهید.

تغییرات دیگری که ممکن است دردسر بسازند

ناوبری و runtime

  • navigateTo اکنون redirect را فقط زمانی برمی‌گرداند که middleware در حال اجراست (#36650) و RouteLocationRaw از نوع بازگشتی عمومی آن پنهان شده است (#36691). کدی که مقدار بازگشتی را بیرون از middleware بررسی می‌کند، یا آن نوع را از این مسیر import می‌کند، محتمل‌ترین کد برای نیاز به تغییر است.
  • ورودی‌های پاک‌شده از _asyncData حذف می‌شوند (#36709) و پاک‌سازی app scope در ناوبری خارجی به تأخیر می‌افتد (#36713).
  • همگام‌سازی CookieStore در useCookie دیگر کوکی را با refresh بازنویسی نمی‌کند (#36673).
  • updateCallbackDone ردشده از یک view transition لغوشده مدیریت می‌شود (#36639).

Nitro

  • با قطع اتصال کلاینت، portable request لغو می‌شود (#36652) و prerender hintها با درخواست‌های self-fetch به اشتراک گذاشته نمی‌شوند (#36705).
  • nitropack به 2.13.5 می‌رود و workaroundهای منسوخ حذف می‌شوند (#36649).

کارایی build

  • بلوک‌های style ساده در build سرور رد می‌شوند (#36711)، Vue در قالب ESM باندل می‌شود و کش‌ها دوباره استفاده می‌شوند (#36710)، و یک بررسی درجه‌دوم پوشهٔ تودرتو برای fs.allow حذف شده است (#36702).
  • لینک‌های سفارشی داخلی بدون RouterLink در سرور رندر می‌شوند (#36707) و تولید typed routes در صورت نیاز نبودن رد می‌شود (#36645).
  • shared/ اکنون جزو هش کش build است (#36704). اگر کد را از طریق shared/ بین app و server به اشتراک می‌گذارید، این از کهنه ماندن build کش‌شده جلوگیری می‌کند.

صفحهٔ انتشار برای هیچ‌کدام از این‌ها عدد benchmark نمی‌دهد؛ پس آن‌ها را جهت‌گیری بدانید، نه بهبود اندازه‌گیری‌شده.

چک‌لیست ارتقا

  1. npx nuxt upgrade را اجرا کنید و lockfile را dedupe کنید. فهرست انتشارها برای انتشار امنیتی 4.5.1 گزینهٔ --dedupe را توصیه کرده بود؛ خود صفحهٔ 4.6.3 دستور ارتقایی نمی‌دهد.
  2. اگر روی 4.6.x هر dev serverی برای دیگران در دسترس بوده، secretهایی را که به app secret تولیدشده وابسته‌اند بچرخانید.
  3. endpoint مربوط به island را برای صفحه‌هایی که redirect rule دارند درخواست کنید و مطمئن شوید redirect می‌شوند.
  4. smoke test مربوط به route ruleها را با مسیرهای دارای حروف مختلط، کاراکتر انکدشده و dot segment اجرا کنید.
  5. دنبال کدی بگردید که مقدار بازگشتی navigateTo را بیرون از middleware به کار می‌برد.
  6. اگر ابزاری خروجی dev Nitro یا secret تولیدشده را از dev server می‌گرفت، انتظار شکست داشته باشید. این رفتار عمدی است.

بده‌بستان‌ها و ملاحظات

  • صفحهٔ انتشار داده‌ای دربارهٔ شدت یا نسخه‌های آسیب‌پذیر ندارد. پیش از تصمیم دربارهٔ فوریت ارتقا به تب Security در GitHub بروید؛ برای اپی که dev server را در معرض نمی‌گذارد، موارد مرتبط با production رفع dot segment و redirect روی islandهاست.
  • چند رفع فقط در چند کلمه توصیف شده‌اند. توصیف من از هشدارها از همان عنوان‌ها آمده، نه متن advisoryها؛ پیش از نقل در یک بازبینی امنیتی سازوکار را در خود advisory بررسی کنید.
  • سخت‌گیرانه‌تر کردن تطبیق route rule جهت درستی است، اما تغییر رفتاری در یک patch release است. بالا رفتن patch در CI به شما نمی‌گوید routeRules هنوز همان چیزی را محافظت می‌کند که فکر می‌کنید؛ فقط تست در سطح درخواست این را نشان می‌دهد.
  • آهنگ انتشار patchها بالاست: 4.6.1، 4.6.2 و 4.6.3 ظرف سه هفته پس از 4.6.0 آمدند. نسخه را pin کنید و آگاهانه ارتقا دهید، نه با بازهٔ شناور.

منابع