قلاب‌هایی که بدون خطا اجرا می‌شوند و با این حال گزارش فایل گمشده می‌دهند معمولاً جای اشتباهی را نگاه می‌کنند، نه اینکه در کار خود شکست بخورند. مسیرهای نسبی در یک اسکریپت نسبت به پوشه کاری فرایند حل می‌شوند و یک سرویس با پوشه کاری‌ای شروع می‌شود که شما انتخاب نکرده‌اید. فایل کنار اسکریپت و فایلی که فرایند باز می‌کند تنها زمانی یک چیزند که چیزی آن‌ها را لنگر کند. همین شکاف بخش بزرگی از شکست‌های قلاب را توضیح می‌دهد که به اشتباه مشکل دسترسی خوانده می‌شوند.

مسیر را پیش از دسترسی‌ها بررسی کنید، چون خطای دسترسی روی فایل اشتباه هنوز همان فایل اشتباه است.

مسیر نسبی نسبت به فرایند حل می‌شود، نه نسبت به فایل

وقتی اسکریپتی open("policy.json") را صدا می‌زند، هسته نام را نسبت به پوشه کاری کنونی فرایند حل می‌کند. هیچ چیز از جای خود اسکریپت در این جست‌وجو شرکت نمی‌کند. OpenVPN قلاب‌ها را از پوشه‌ای آغاز می‌کند که خودش انتخاب می‌کند، و گزینه cd می‌تواند آن را تغییر دهد، بنابراین اسکریپتی که دستی از پوشه خودش آزمایش شده، وقتی دیمن آن را اجرا می‌کند رفتار دیگری دارد. آزمایش دستی قبول می‌شود، اجرای سرویس شکست می‌خورد و خط گزارش فقط نام گمشده را ذکر می‌کند.

پایتون جای اسکریپت را به صورت __file__ آشکار می‌کند و همین لنگر کردن را ممکن می‌سازد. Path(__file__).resolve().parent / "policy.json" مسیری از فایل می‌سازد نه از فرایند. همین یک خط وابستگی به پوشه کاری را بدون تغییر هیچ چیز در اختیارها حذف می‌کند.

مسیر را آگاهانه لنگر کنید، سپس بررسی کنید که resolve چه می‌کند

resolve() پیوندهای نمادین را دنبال می‌کند، پس نصبی که قلاب را در جای خودش پیوند می‌کند در مقصد پیوند لنگر می‌شود، نه در پوشه‌ای که پیوند را نگه می‌دارد. این معمولاً برای استقرار نسخه‌دار آن چیزی است که می‌خواهید و برای چیدمانی که داده را کنار پیوند نمادین انتظار دارد نادرست است. تصمیم بگیرید که استقرار کدام را می‌خواهد و کد را متناسب با آن بنویسید، نه اینکه تفاوت را در محیط عملیاتی کشف کنید. Path(__file__).parent بدون resolve() پوشه خود پیوند را نگه می‌دارد.

اگر داده به نمونه تعلق دارد نه به برنامه، مسیر مطلقی از پیکربندی بگیرید. سخت‌کد کردن یک مکان قلاب را به یک چیدمان میزبان می‌بندد.

چهار مرز را به ترتیب بگذرانید

با پوشه کاری شروع کنید: WorkingDirectory واحد را، گزینه cd در OpenVPN را و هر پوشانه‌ای که پیش از exec پوشه را عوض می‌کند مقایسه کنید. سپس مکان حل‌شده را تأیید کنید، چون فایلی با نام مشابه در استقرار دیگر می‌تواند به جست‌وجو پاسخ دهد و خطا را پنهان کند. بعد نمای نظام فایل‌ها می‌آید: یک chroot یا فضای نام mount سرویس می‌تواند مسیر مطلق میزبان را به سادگی غایب کند. آخرین مورد هویت دسترسی است که پرسشی جدا از دیدپذیری است.

ProtectHome و PrivateTmp مکان‌های متفاوتی را پنهان می‌کنند و هیچ‌کدام در فهرست پوشه‌ای که از میزبان گرفته شده دیده نمی‌شود. مسیری که برای root در یک پوسته وجود دارد می‌تواند درون فضای نام واحد نامرئی باشد، و به همین دلیل آزمایش همان فرمان بیرون از سرویس چیز بسیار کمی را اثبات می‌کند.

جست‌وجو را بدون گسترش سرویس درست کنید

لنگر کردن مسیر فقط مرز نخست را حل می‌کند. پوشه‌ای را که سرویس پنهان می‌کند آشکار نمی‌کند و به حسابی بدون اختیار دسترسی به فایلی که فقط برای root است نمی‌دهد. بالا بردن script-security تغییر می‌دهد که OpenVPN کدام اسکریپت‌ها را اجرا کند; هیچ تأثیری بر جایی که نام نسبی حل می‌شود ندارد. تغییر پوشه کاری برای تمام سرویس گسترده‌تر از مشکل است، چون هر مسیر نسبی دیگر برای گواهی، گزارش یا ابزار کمکی با آن جابه‌جا می‌شود.

اصلاح باریک را ترجیح دهید: مسیری قطعی در اسکریپت، مقدار پیکربندی صریح برای داده نمونه، و مالکیت فایلی که با حسابی که قلاب واقعاً با آن اجرا می‌شود همخوان باشد.

شواهدی ثبت کنید که مرز را نام می‌برد

گزارش شکست سودمند سه چیز دارد: مسیر دقیقی که قلاب کوشید، محیطی که آن را پدید آورد و کدام مرز رد کرد. مسیر حل‌شده و استثنا را بدون ریختن محتوای فایل چاپ کنید. این سه‌گانه لنگر اشتباه را از mount پنهان و از رد دسترسی جدا می‌کند و این‌ها سه اصلاح متفاوت‌اند.

این ادعا که root می‌تواند فایل را از یک ترمینال بخواند به یکی از آن پرسش‌ها پاسخ می‌دهد و به هیچ‌یک از بقیه نه. به جای آن از بافت خود سرویس آزمایش کنید.

مقالات مرتبط