یک درخواست شکستخورده را از کجا بررسی کنیم؟
فرض کنید برنامه موبایل تیم شما هنگام ارسال تصویر پروفایل خطای مبهمی نشان میدهد. همان فایل از نسخه وب با موفقیت ارسال میشود. همکار سمت سرور میگوید درخواست به مسیر مورد انتظار نرسیده و توسعهدهنده موبایل مطمئن است دکمه ارسال کار میکند. در این وضعیت، مقایسه درخواست واقعی دو کلاینت مفیدتر از حدس درباره کتابخانه شبکه است. mitmproxy یک پراکسی تعاملی برای مشاهده و بررسی تبادل HTTP در محیط آزمایش است. با آن میتوانید مسیر، روش درخواست، سرآیندها و پاسخ دریافتی را کنار هم ببینید و نخستین تفاوت مرتبط را پیدا کنید.
در این راهنما از یک سرویس آزمایشی متعلق به تیم و حسابی با داده غیرواقعی استفاده میکنیم. هدف، پاسخ دادن به یک سؤال محدود است. آیا درخواست موبایل با همان نام فیلد و همان نوع محتوا به همان مسیر میرسد؟ چنین سؤالی تعیین میکند چه دادهای برای آزمایش لازم است و چه چیزی اصلاً نباید ثبت شود. وقتی مسئله فقط مقایسه نام فیلد است، نیازی به ثبت نشست واقعی کاربر یا نگهداری طولانی محتوای تصویر وجود ندارد.
سه رابط برای سه نوع کار
پروژه سه ابزار با نقشهای مرتبط ارائه میکند. mitmproxy رابط تعاملی کنسول است و برای باز کردن جریانهای درخواست و پاسخ مناسب است. mitmweb همین نوع کار را در یک رابط تحت وب در اختیار کاربر قرار میدهد. mitmdump برای کار خط فرمان و آزمایشهایی مفید است که باید بدون تعامل طولانی با صفحه اجرا شوند. انتخاب رابط باید بر اساس نوع کار انجام شود. برای نخستین بررسی یک خطای قابل بازتولید، رابط تعاملی کمک میکند چند درخواست را کنار هم مرور کنید. برای تکرار کنترل در خط آزمایش، خروجی محدود و قابل پردازش ارزش بیشتری دارد.
برای مثال، اگر برنامه هنگام باز شدن چندین سرویس را فراخوانی میکند، نگاه کردن به همه جریانها به ترتیب ورود میتواند گیجکننده باشد. با دامنه و مسیر آزمایشی شروع کنید و زمان دقیق فشردن دکمه را ثبت کنید. سپس پاسخ همان درخواست را با رخداد ثبتشده سمت سرور تطبیق دهید. تفاوت میان ارسال نشدن درخواست، دریافت پاسخ خطا و خطای رابط کاربر پس از دریافت پاسخ، مسیر رفع اشکال را کاملاً عوض میکند.
چرا پراکسی ساده محتوای HTTPS را نمیبیند؟
در پراکسی صریح HTTP، کلاینت میداند باید درخواست را به پراکسی بفرستد و مقصد را در درخواست مشخص میکند. برای HTTPS، کلاینت معمولاً از روش CONNECT استفاده میکند تا یک تونل تا میزبان مقصد برقرار شود. در یک پراکسی عبوری معمولی، محتوای رمزگذاریشده از داخل این تونل میگذرد و پراکسی نمیتواند بدنه درخواست را بخواند. دیدن موفقیت CONNECT بهتنهایی نشان نمیدهد محتوای HTTPS قابل بررسی شده است.
mitmproxy برای تحلیل HTTPS آزمایشی دو ارتباط برقرار میکند. یک ارتباط TLS میان کلاینت و پراکسی و ارتباط دیگری میان پراکسی و سرور مقصد شکل میگیرد. پراکسی برای سمت کلاینت گواهی متناسب با نام مقصد ارائه میکند. کلاینت باید مرجع صادرکننده آزمایشگاه را برای این منظور معتبر بداند. سمت دیگر ارتباط نیز باید هویت سرور واقعی را درست بررسی کند. در نتیجه، دو شکست متفاوت ممکن است رخ دهد. برنامه میتواند گواهی سمت پراکسی را نپذیرد یا خود پراکسی نتواند ارتباط معتبر با مقصد ایجاد کند.
آمادهسازی یک کلاینت آزمایشی
آزمایش را با پروفایل جداگانه مرورگر یا دستگاه آزمایشی شروع کنید. آدرس و درگاه پراکسی را در تنظیمات همان کلاینت وارد کنید و ابتدا رسیدن یک درخواست ساده به رابط ابزار را بررسی کنید. اگر کلاینت و پراکسی روی یک دستگاهاند، آدرس حلقه محلی معمولاً انتخاب طبیعی است. روی گوشی، آدرس حلقه محلی به خود گوشی اشاره میکند. برای پراکسی در لپتاپ باید از نشانی قابل دسترس همان لپتاپ در شبکه آزمایش استفاده شود و مسیر شبکه و فایروال نیز این ارتباط را مجاز بدانند.
مرجع آزمایشی را فقط در محدودهای نصب کنید که برای آزمایش لازم است. فایل گواهی عمومی با کلید خصوصی صادرکننده تفاوت دارد و کلید خصوصی نباید همراه راهنمای تیم منتشر شود. پس از آزمایش، تنظیم پراکسی و اعتماد آزمایشی را از پروفایل مربوط بردارید. اگر حذف تنظیم پراکسی فراموش شود، برنامه ممکن است روز بعد با خاموش شدن لپتاپ از کار بیفتد و تیم آن را خطای سرور تلقی کند. ثبت مراحل بازگرداندن محیط از همان ابتدا هزینه چنین ابهامی را کم میکند.
اولین مشاهده بدون تغییر درخواست
برای شروع روی همان رایانه، میتوانید ابزار را روی یک درگاه محلی در دسترس کلاینت آزمایش اجرا کنید. اگر این درگاه از قبل اشغال است، یک درگاه آزاد انتخاب کنید و همان مقدار را در تنظیمات کلاینت وارد کنید.
mitmproxy --listen-host 127.0.0.1 --listen-port 8080
ابتدا یک درخواست ساده به سرویس آزمایش بفرستید و در رابط ابزار، میزبان، مسیر، روش و وضعیت پاسخ را بررسی کنید. به جای ثبت همه بدنهها، یک شناسه غیرحساس برای درخواست آزمایشی تعیین کنید تا بتوانید آن را در گزارش سرور پیدا کنید. اگر زمان ثبت سرور و کلاینت متفاوت است، اختلاف ساعت را نیز یادداشت کنید. اولین نتیجه مورد انتظار یک جریان کامل درخواست و پاسخ است. اگر تنها تلاش برای اتصال دیده شود، هنوز نوبت بررسی محتوای JSON یا فیلدهای فرم نرسیده است.
سپس همان عمل را از نسخهای که سالم کار میکند انجام دهید. برای مقایسه، فایل ورودی، حساب آزمایش، نسخه API و محیط سرور را ثابت نگه دارید. اگر همزمان چند متغیر عوض شوند، پیدا شدن یک تفاوت دلیل کافی برای علت خطا نیست. مثلاً پاسخ متفاوت ممکن است به نقش حساب مربوط باشد، حتی اگر دو درخواست از نظر بدنه شبیه به هم باشند. هر تغییر را جدا اعمال کنید و نتیجه را در قالب یک پرسش قابل بازآزمایی بنویسید.
مثال ارسال تصویر با multipart
در مثال پروفایل، درخواست سالم ممکن است تصویر را در فیلدی با نام avatar بفرستد و درخواست خراب از نام file استفاده کند. هر دو اتصال TLS سالماند و هر دو بدنه دارند، اما قرارداد API فقط یکی از نامها را میشناسد. در پراکسی، نوع محتوا، نام بخش، نام فایل و پاسخ خطای سرور را بررسی کنید. اگر سرور پاسخ ساختاریافتهای درباره فیلد گمشده میدهد ولی برنامه فقط «خطا» نشان میدهد، دو اصلاح جداگانه ممکن است لازم باشد. نخست ساخت درخواست درست و سپس نمایش پیام قابل فهم به کاربر.
مرز multipart نیز بخشی از قرارداد انتقال است. وقتی کتابخانه کلاینت بدنه را تولید میکند، تعیین دستی سرآیند نوع محتوا بدون پارامتر لازم میتواند تحلیل بدنه را برای سرور دشوار کند. از مشاهده درخواست موفق برای فهم ساختار استفاده کنید و ساخت مرز را تا حد امکان به کتابخانه استاندارد بسپارید. همچنین تفاوت میان حجم واقعی فایل، حجم کل درخواست و محدودیت پراکسی بالادستی را در نظر بگیرید. پاسخ مربوط به اندازه ممکن است پیش از رسیدن به خود برنامه ایجاد شود و در آن حالت گزارش برنامه هیچ رخدادی نخواهد داشت.
تفسیر خطای گواهی و نام میزبان
بررسی TLS فقط با دانستن اینکه یک گواهی در دستگاه نصب شده تمام نمیشود. بعضی کلاینتها از مخزن اعتماد سیستم استفاده میکنند و بعضی تنظیم مستقل دارند. برنامه آزمایشی ممکن است سیاست خاصی برای گواهیهای کاربر یا تطبیق هویت مقصد داشته باشد. اگر مرورگر کار میکند و برنامه همان دستگاه خطا میدهد، نخست سیاست اعتماد همان برنامه و نسخه آزمایشی آن را بررسی کنید. این تفاوت بهتنهایی اثبات نمیکند سرور اصلی گواهی نامعتبر دارد.
نام میزبان نیز اهمیت دارد. طبق مستندات پروژه، اطلاعات اتصال و گواهی بالادستی در ساخته شدن گواهی مناسب نقش دارند. روی میزبانی که چند دامنه را میزبانی میکند، SNI به انتخاب گواهی درست در ارتباط بالادستی کمک میکند. اگر سرویس آزمایشی از یک نام سفارشی استفاده میکند، DNS و نام موجود در گواهی را با نامی که کلاینت واقعاً درخواست کرده مقایسه کنید. خاموش کردن بررسی گواهی در نسخه عملیاتی علت را پنهان میکند و شرایط آزمون را از شرایط واقعی دور میسازد.
بازپخش و پیامد درخواستهای دارای اثر
توانایی مشاهده و بازپخش درخواست برای تست رگرسیون مفید است، اما رفتار همه درخواستها یکسان نیست. بازپخش پرسوجوی خواندن معمولاً با ایجاد دوباره سفارش یا ارسال دوباره ایمیل تفاوت دارد. برای تمرین، از حساب و داده اختصاصی و مسیری استفاده کنید که پیامد آن قابل کنترل باشد. اگر API شناسه یکتای عملیات یا کلید جلوگیری از تکرار دارد، رفتار آن را عمداً آزمایش کنید. اجرای دوباره همان درخواست باید نتیجه قابل توضیح داشته باشد و گزارش سرور باید نشان دهد چند عملیات واقعی رخ داده است.
پس از مشاهده یک درخواست خراب، میتوان یک متغیر مشخص را در یک نسخه آزمایشی عوض کرد و نتیجه را دید. مثلاً فقط نام فیلد فایل را مطابق قرارداد API اصلاح کنید. اگر پاسخ موفق شد، آزمایش بعدی باید همان اصلاح را در کد کلاینت انجام دهد و بدون تغییر پراکسی دوباره نتیجه را بررسی کند. این مرحله فرق میان یافتن فرضیه و اثبات اصلاح واقعی است. پراکسی میتواند مشکل را برای یک درخواست بهطور موقت پنهان کند، اما تجربه کاربر تنها پس از اصلاح مسیر عادی برنامه بهبود مییابد.
کاهش داده ثبتشده و تحویل گزارش خطا
جریان HTTP ممکن است شامل کوکی نشست، توکن دسترسی، شماره تماس، آدرس ایمیل یا فایل خصوصی باشد. پیش از اشتراک گزارش، تعیین کنید چه چیزی واقعاً برای بازتولید لازم است. برای پرونده ارسال تصویر، نام فیلد، مسیر، وضعیت و چند خط از پاسخ بیحساسیت معمولاً کافیاند. بدنه فایل و اعتبارنامه را با داده آزمایشی جایگزین کنید. تصویر صفحه ابزار نیز ممکن است سرآیند حساس را نشان دهد، پس فقط حذف یک خط از متن گزارش کافی نیست. هر پیوست باید جدا بازبینی شود.
یک گزارش قابل استفاده شامل نسخه برنامه، زمان آزمایش، نقش کاربر آزمایشی، رفتار مورد انتظار، رفتار مشاهدهشده و تفاوت مشخص میان جریان سالم و خراب است. افزودن شناسه درخواست به تیم سمت سرور کمک میکند همان رخداد را پیدا کند. اگر مشکل به مرحله TLS مربوط است، نوع خطا و اینکه کدام طرف ارتباط آن را گزارش کرده بنویسید. اگر مشکل به پاسخ API مربوط است، کد وضعیت و بخش غیرحساس پاسخ را ثبت کنید. این تفکیک کمک میکند گزارش به تیم مسئول برسد و زمان صرف بازسازی حدسهای قبلی نشود.
معیار پایان آزمایش
کار زمانی تمام میشود که همان نسخه اصلاحشده برنامه، از مسیر عادی خود و بدون دستکاری جریان، درخواست مناسب بفرستد و نتیجه مورد انتظار را دریافت کند. برای این مثال، تصویر باید روی سرور آزمایشی ذخیره شود، پاسخ توسط برنامه درست تفسیر شود و بارگذاری دوباره صفحه همان تصویر را نشان دهد. سپس آزمایش یک فایل نامعتبر یا بیش از حد مجاز را نیز انجام دهید تا مسیر خطا پیام روشن داشته باشد. این دو نتیجه نشان میدهند هم رفتار موفق و هم شکست قابل پیشبینی بررسی شده است.
در پایان، پراکسی را از تنظیمات کلاینت بردارید و یک درخواست عادی به مقصد آزمایش بفرستید تا بازگشت محیط تأیید شود. فقط شواهد لازم را با مدت نگهداری مشخص حفظ کنید و بقیه جریانهای آزمایشی را از محل مشترک تیم کنار بگذارید. ارزش اصلی mitmproxy در این سناریو تبدیل یک خطای مبهم به تفاوتی قابل مشاهده و قابل آزمایش است. وقتی مسیر، هویت، بدنه و پاسخ جدا بررسی شوند، رفع مشکل به یک تغییر مشخص در کلاینت، سرور یا تنظیم اتصال منتهی میشود.