حسین طالقانی
حسین طالقانی
خواندن ۱۶ دقیقه·۹ ماه پیش

چند درس مهندسی نرم‌افزار از سیستم دریافت نوبت ارز دولتی صرافی ملی

دولت تصمیم می‌گیره ارز رو برای مدتی نامعلوم با قیمتی ثابت عرضه کنه؛ احتمالاً به این امید که قیمت بازار رو کنترل کنه. قیمت بازار،‌ روز به روز بالا میره؛ و یک جایی مثل امروز، در حالی که دلار در بازار بالاتر از ۵۸ هزار تومنه، دلار دولتی حدود ۴۵ هزار تومن (با احتساب کارمزد) برای شما آب می‌خوره. با ضرب اختلاف این دو عدد در ۲۱۰۰ دلار که به هر فرد داده میشه، متوجه می‌شین می‌تونین [تقریباً] در یک چشم به هم زدن ۲۷ میلیون تومن کاسب بشین! مشخصه که همچین عددی هر آدم عاقلی رو وسوسه می‌کنه که هر طور شده ۹۵ میلیون تومن جور کنه تا از این حاتم‌بخشی دولت بی‌نصیب نمونه.

حالا که این میزان تقاضا شکل گرفته، دولت یادش می‌افته که انقدر منابع ارزی نداره که به هر کسی درخواست کرد، اسکناس بده. پس با اعطای سهمیه به [برخی؟] صرافی‌ها، ورودی رو کنترل می‌کنه و اینطوری یه رقابت شکل می‌گیره:‌ رقابت برای دسترسی به سهمیه محدود صرافی‌ها. به احتمال خیلی زیاد، دست من و شما که به این سهمیه نمی‌رسه (مگر اینکه شما آشنا داشته باشی 😉). امّا فکر اینجا رو هم کردن:‌ با ارائه نوبت اینترنتی، عدالت [در دسترسی] برقرار میشه. کافیه به «سامانه نوبت‌دهی صرافی ملی» سر بزنید و نوبت بگیرید. برای افزایش عدالت دسترسی (یا شاید هم هیجان!) این بند هم اضافه می‌شه که: ساعت ۱۶ هر روز (و پنجشنبه‌ها ۱۲)، نوبت‌های روز کاری بعد فعال میشه.

شما و بقیه شهروندهای متمدن چند دقیقه قبل از ساعت اعلام شده وارد سایت می‌شین،‌ شرایط و قوانین رو می‌پذیرید و به مرحله بعد می‌رید و منتظر وقت موعود می‌مونین تا روی دکمه «جستجوی نوبت» بزنین و...حالا مسابقه تبدیل میشه به ثبت نوبت توی سایت: چند صدهزار (شاید هم چند میلیون) درخواست رأس یک ساعت برای دستیابی به ۸۰-۹۰ نوبت. فرآیند به این شکل طراحی شده:

  • یک نوبت انتخاب می‌کنین،
  • شماره موبایل‌تون رو وارد می‌کنین، و منتظر دریافت کد یک‌بار مصرف (OTP) می‌شین،
  • کد رو وارد می‌کنین و در صورت تایید به شما اعلام می‌شه روند تکمیل ثبت‌نام براتون پیامک می‌شه
  • لینک یک فرم (با شناسه مخصوص شما) براتون ارسال می‌شه که با وارد کردن اسم، فامیل، جنسیت، ملیت (اصلاً مگه به غیرایرانی هم میدن این ارز رو؟!)‌، کد ملی، تاریخ و محل تولد، آدرس، کدپستی، شماره موبایل (مگه تو مرحله قبل نگرفتن!؟)، تلفن ثابت و مقدار و نوع ارز درخواستی، و ثبت فرم، برنده یک دستگاه نوبت می‌شین!
تمام این اطلاعاتی که از شما گرفته میشه رو وقتی تشریف می‌برید صرافی باید تو یه فرم کاغذی پر کنین! نه فقط اطلاعات، که صرافی حتی به ساعتی که رزرو کردین هم کاری نداره و همونجا مثل بانک نوبت میده بهتون! با این تفاسیر، به نظر چرا این اطلاعات رو اینجا باید وارد کنین؟

امّا این حالت ایده‌آل ماجراست. در واقعیت، یکی از این چند حالت اتفاق می‌افته:

  • فقط ۲-۳ دقیقه بعد از زمان اعلام شده پروسه رو شروع می‌کنین و می‌بینین هیچ نوبتی وجود نداره. البته فهمیدن این هم بار اول یکم سخته؛ چون برنامه‌نویس محترم به UX اعتقادی نداشته و نوبت‌های غیرفعال رو هم نشون می‌ده، امّا ۲۰ درصد کم‌رنگ‌تر از سایر دکمه‌ها! البته جهت رفاه حال شما پایین صفحه و بعد از این ۸۰-۹۰ دکمه‌ی زمان‌های نوبت، با رنگ قرمز نوشته: نوبتی یافت نشد.
  • بار بعد به موقع وارد سایت می شین و نوبت رو انتخاب و شماره‌تون رو وارد می‌کنین و تیک «من ربات نیستم» رو می‌زنین و منتطر دریافت کد می‌شین. امّا شمارش معکوس تموم میشه و شما یا هیچ کدی دریافت نمی‌کنین، یا انقدر دیر کد رو دریافت می‌کنین که تاریخ انقضاش گذشته.
  • این بار خیلی خوش شانس هستین و کد رو وارد می‌کنین و تایید می‌شه. حالا منتظر دریافت پیامک می‌مونین...ولی یا دریافت نمی‌کنین، یا وقتی دریافت می‌کنین، بهتون میگه لینک منقضی شده (چون زمان داره و خیلی دیر به دست شما رسیده)، یا دریافت می‌کنین و تا میاین اون همه اطلاعات رو (که هیچ جا هم استفاده نمی‌شه) وارد کنین و باز هم «من ربات نیستم» رو بزنین (که ممکنه نیاز به حل کردن یه چالش reCAPTCHA داشته باشه و زمان ببره)، لینک منقضی می‌شه یا اگر منقضی نشه هم به شما اعلام میشه «نوبت وجود ندارد» (که یعنی شخص دیگه‌ای همین نوبت رو گرفته).
در قدم ورود اطلاعات مشکلات دیگه‌ای هم وجود داره و اون اینه که قواعد درستی برای ورودی تعریف نشده. برای نمونه، آدرس فقط می‌تونه شامل حرف باشه و مثلاً شما نمی‌تونی بنویسی «خیابان فردوسی، پلاک ۲۷۰» (چون ویرگول و عدد داره!). البته این دربرابر افتضاح کل سیستم که در ادامه مفصل بهش می‌پردازم، هیچ به حساب میاد.
  • شما که از داستان مور و تیمور، درس استقامت گرفتی، برای بار چندم مجهزتر از همیشه وارد فرآیند می‌شی. این بار همه اطلاعات رو از قبل جایی نوشتی (که فقط کپی کنی)، و بدون معطلی همه مراحل رو طی می‌کنی...امّا باز هم نوبت بهت نمی‌رسه!

چند روز به همین منوال می‌گذره و بعد، شما که آدم اهل فکر و حساب‌وکتابی هستی، با خودت می‌گی: بعیده آدمی سریع‌تر از این بتونه فرآیند رو طی کنه؛ پس چطوری نوبت گیرم نیومد؟ حتماً اینا رو دارن به آشناهاشون میدن... ولی دادن به آشنا که این همه فرآیند و سیستم و هزینه پیامک و... نیاز نداره! پس نکنه... بله حدس‌تون درسته: شما با آدم‌های دیگه رقابت نمی‌کنین. با کامپیوترهای دیگه (یا همون ربات‌ها) دارین رقابت می‌کنین. امّا چطور ممکنه؟ مگه کپچا و «ربات نیستم» برای جلوگیری از همین نیست؟

بعد یه چرخ توی توییتر و تلگرام می‌زنین و می‌بینین بله، ربات هست براتون نوبت می‌گیره، ۳-۵ میلیون تومن. (یاد «ربات درست کردن با انسان مناظره می‌کنه» شاهین نجفی افتادم 😀) ممکنه قیمت زیادی به نظر بیاد، امّا وقتی یادتون بیاد که قراره ۲۷ میلیون تومن کاسب بشین، با خودتون می‌گین ۳ تومن بدم و ۲۴ تومن گیرم بیاد بهتر از اینه که هیچی ندم و هیچی گیرم نیاد. امّا چون مهندس خوبی هستین، با خودتون می‌گین: اگه یکی دیگه تونسته، حتماً من هم می‌تونم!


شروع ماجراجویی با دنبال کردن خرگوش سفید

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

اولین موضوعی که باید ازش سر در بیارین، اینه که چطوری ربات‌ها از سد CAPTCHA میگذرن؟ پس روز بعدی که می‌خواین پروسه رو طی کنین، Developer Tools مرورگر رو باز می‌کنین و درخواست‌هایی که به سرور فرستاده می‌شه رو نگاه می‌کنین. در کمال تعجب و ناباوری، پاسخ reCAPTCHA به سرور فرستاده نمی‌شه و صرفاً فعال/غیرفعال شدن دکمه فرم توی UI رو کنترل می‌کنه. پس شما می‌تونین بدون هیچ محدودیتی APIها رو فراخوانی کنین.

اصلاً شروع ماجراجویی من وقتی بود که دیدم امید توی توییتی به این موضوع اشاره کرده که ریکپچاها دکوره.
جوری که برنامه‌نویس از کپچا استفاده کرده: Useless Gate
جوری که برنامه‌نویس از کپچا استفاده کرده: Useless Gate

از اینجا به بعد دیگه به نسبت سرراسته: باید درخواست‌هایی که طی فرآیند به سرور فرستاده می‌شه رو پیدا کنین و بعد یه برنامه بنویسین که سر ساعت مورد نظر، فرآیند رو اجرا کنه. این کار رو دو جور می‌تونین انجام بدین:

  • با طی کردن فرآیند توی مرورگر و دیدن درخواست‌ها، که فقط روزی یک بار برای دقایق محدود ممکنه و تازه اگر شانس بیارین بتونین کل فرآیند رو طی کنین.
  • با خوندن کدهای JS. درسته که کدها با webpack تیکه تیکه و ناخوانا شدن، ولی پیدا کردن مسیر اجرا با debugger مرورگر و/یا با دنبال کردن کد خیلی سخت نیست.

درخواست‌ها به این شرح هستن:

  • ایجاد یه session جدید که فقط تا ۲ دقیقه معتبره. برای استفاده از این session توی درخواست‌های بعدی، باید توکنی که توی کوکی به شما داده می‌شه رو بفرستین.
  • دریافت لیست نوبت‌ها. با ارسال تاریخ مورد نظر، آرایه‌ای از نوبت‌ها با قالب زیر به شما برمی‌گردونه. خالی (null) بودن CUSTOMER_ID به معنی اینه که نوبت رو کسی نگرفته (و در دسترس شماست)
{'ID': 8704, 'TURNTIME': '14:00', 'CUSTOMER_ID': 9108, 'ISACTIVE': 'Y'}
  • درخواست OTP با ارسال شناسه (ID) یک نوبت و شماره موبایل
  • ثبت کد با ارسال نوبت و شماره موبایل
  • ثبت فرم با ارسال اطلاعات مورد نظر (اسم و فامیل و...) و شناسه فرم (که در لینکی که دریافت کردین قرار داره)

با توجه به اینکه یک قسمت از فرآیند از موبایل می‌گذره، باید به یه نحوی بتونین پیامک‌ها رو بخونین و مرحله بعد رو اجرا کنین (حالا یا همون سمت موبایل، یا با رسوندن پیام به کدی که دارین). این کار هم به نسبت ساده‌ست:

  • روی اندروید که هر برنامه‌ای می‌تونه دسترسی پیامک بگیره. مثلاً می‌تونین با یه برنامه خودکارسازی (مثل MacroDroid) یه automation تعریف کنین که «با دریافت پیامک از فلان شماره، بهمان API رو فراخوانی کن». یا می‌تونین خودتون یه برنامه خیلی کوچیک بنویسین که همین کار رو انجام بده.
  • روی iOS (آیفون) برنامه‌ها نمی‌تونن دسترسی پیامک بگیرن. امّا با کمی جستجو متوجه می‌شین که با اپ Shortcuts که روی خود سیستم عامل وجود داره، می‌تونین یه automation تعریف کنین که شروع (trigger) اون با دریافت یه پیامک باشه و ادامه‌اش هم که مثل اندروید، فراخوانی یه API میتونه باشه.


کدوم قدم‌ها رو می‌تونم دور بزنم؟

در ابتدا با کمی دقت متوجه می‌شین شناسه نوبت‌ها پشت سر هم هستن. اگر آخرین نوبت امروز (که روز قبل داده شده) n باشه، نوبت‌های فردا از n+1 شروع می‌شه تا n+85. یعنی شما می‌تونین از دریافت لیست نوبت‌ها بگذرین و یک‌راست یه عدد تصادفی در این بازه انتخاب کنین و براش درخواست کد تایید بدین. چون بدون شک تو اون زمانی که شما دارین برای بار اول لیست نوبت‌ها رو می‌گیرین، تمام نوبت‌ها آزاد هستن. امّا این API می‌تونه یه نقش دیگه رو برای ما ایفا کنه: از اونجایی که ساعت ما و سرور مورد نظر کاملاً منطبق نیست و سرور هم احتمالاً نوبت‌گیری رو با یه Cron Job شروع می‌کنه که اون هم لزوماً‌ رأس ساعت (= ثانیه صفر) کار رو انجام نمی‌ده، شما با رصد (monitor) کردن این API توی یه حلقه، می‌تونین متوجه بشین نوبت‌دهی دقیقاً کی شروع میشه (این برای مرحله بعد، حیاتیه)

مرحله بعد، درخواست و ثبت OTPـه. اولین ایده‌ای که برای دور زدن این دو درخواست به ذهن میاد، امتحان کردن همه حالت‌هاست (brute force). خوشبختانه (؟) تا حد خوبی جلوی این موضوع با Rate Limiting و محدودیت «یک درخواست در دقیقه» گرفته شده. امّا این محدودیت، نه روی کلاینت که روی شماره موبایله. اگر قبل از شروع نوبت‌دهی درخواست بدین، اگرچه که نوبتی وجود نداره و خطا دریافت می‌کنین، ولی تا یک دقیقه بعد نمی‌تونین درخواست بدین. به همین خاطر فهمیدن زمان دقیق شروع نوبت‌دهی حیایته.

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

با کمی آزمون و خطا متوجه می‌شین که این «یک دقیقه» معادل ۶۰ ثانیه نیست، بلکه ۷۰ ثانیه‌ست 🤭 و از آخرین درخواست شما هم حساب می‌شه. یعنی اگر درخواست دوم رو ۶۹ ثانیه بعد از درخواست اول بدین، نه تنها خطای محدودیت تعداد درخواست می‌گیرین، بلکه دوباره از نو ۷۰ ثانیه رو می‌شمره! حتی اگر خطا از سمت سرور باشه هم (مثل محدودیتی که در بند بعد درباره‌ش می‌کنم) باز شما از درخواست مجدد منع می‌شین.

علاوه‌بر این، متوجه می‌شین طراح سیستم (که یادش رفته در رو روی ربات‌ها ببنده) یه مانع خیالی دیگه گذاشته: تا ۱۰ ثانیه بعد از شروع نوبت‌دهی، شما نمی‌تونین OTP درخواست کنین. نمی‌دونم دقیقاً‌ چه تصوری داشته، ولی این کار صرفاً باعث میشه یه خط sleep(10) به کد اضافه بشه. یا حتی اگر زمانش رو ندونیم، با توجه به اینکه با شماره‌های دیگه می‌شه درخواست دارد، با یه حلقه شماره‌های مختلف رو انقدر تکرار می‌کنین تا دیگه خطای «مجاز به فراخوانی سرویس در این بازه زمانی نمی باشید.» نگیرین و بعد با شماره خودتون درخواست می‌دین.

با توجه به این مشاهده که در انتهای فرآیند خطای «نوبت وجود ندارد» داده می‌شه، می‌تونیم نتیجه بگیریم که یا رزروی وجود نداره یا زمان رزرو کوتاه‌تر از طی کردن کل فرآیند (حتی توسط ربات) تعیین شده. علاوه بر این، با دیدن نوبت‌های روزهای قبل می‌بینیم که برای برخی زمان‌ها بیش از یک نوبت وجود داره (مثلاً ۲تا ۰۸:۴۵ داریم). این یعنی کنترلی روی یکتا بودن ساعت و روز وجود نداره. مجموع این موارد من رو نگران می‌کنه که ممکنه جلوی Lost Update رو هم نگیرن.

به هر صورت، تو مرحله دریافت کد خیلی کار خاصی نمی‌تونیم بکنیم، جز اینکه در سریع‌ترین زمان ممکن کد رو دریافت و ثبت کنیم. مرحله ثبت فرم از این هم سخت‌تر به نظر میاد: اگر اینجا با یه کد عددی ۶ رقمی روبه‌رو هستیم، اونجا با یه رشته طولانی روبه‌رو هستیم (یه hash). ممکنه اگر زمان بگذارین ببینین چیزی هست که قابل بازیابیه ¯\_(ツ)_/¯

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


کنجکاوی بیش‌تر
توی گشت‌وگذار توی کد، به یک سری endpoint می‌بینین که نه هیچ وقت فراخوانی شدن، و با فراخوانی‌شون هم به نظر میاد که چیزی اونجا نیست. از خودتون می‌پرسین: آیا به خاطر محدودیت دسترسی جوابی نمی‌گیرم؟ یا کد متروک مربوط به یه نسخه قدیمیه؟ یا ...؟
وقتی کانال یکی از ربات‌های دریافت نوبت توی تلگرام اسکرین‌شات صفحه پیام‌های کسایی که براشون نوبت گرفته بود رو گذاشت، نظرم به این جلب شد که قبل از ساعت شروع نوبت‌دهی، برای افراد پیامک کد ارسال شده از همین سرشماره. با بررسی بیش‌تر سایت، متوجه می‌شین که این سرویس پیش از این، به جای زیردامنه nobat.mex.co.ir روی دامنه mex.co.ir بالا بوده و هنوز هم سرویس قبلی APIهاش در دسترسه. از جمله اینکه شما می‌تونین با فراخوانی APIها توش ثبت‌نام کنین (که کار بی‌خاصیتیه) یا حتی درخواست OTP بدین (بدون اینکه نوبتی وجود داشته باشه یا نوبت‌دهی فعال باشه). این دومی رو کانال مربوطه برای تست برنامه‌ای که برای موبایل به مشتری‌ها داده بود استفاده می‌کرد: کافیه یه درخواست به این API بدین و ببینین که آیا برنامه‌ای که روی موبایل نصب کردین کد رو به سرور شما می‌فرسته یا نه.
علاوه‌بر این، یک API برای دریافت تنظیمات و/یا محتوای dynamic از سرور تعریف شده بود (که کار مرسومیه) ولی یکی از مواردی که توی جواب ارائه می‌کرد، موجودی پنل پیامکی بود! (که این واقعاً عجیبه!)


اشتباهات این سیستم و درس‌هایی برای ما

یکی از سوال‌هایی که برای مصاحبه‌ها می‌پرسیدم، سناریویی نزدیک به همین مسئله بود: یک رقابت [شدید] برای منابع محدود. این سوال رو دوست داشتم به این خاطر که علیرغم ظاهر ساده‌ش، نکات ریزی داشت که رعایت نکردنشون منجر به درست کار نکردن سیستم می‌شد، و همین موارد فرصت‌هایی برای پرسش و گفتگو درباره موضوعات مهندسی به وجود میاورد. اینجا علاوه بر اون موارد، با چند مشکل دیگه هم روبه‌رو هستیم. تازه این‌ها مواردی از نگاه کسی که تخصص امنیت و نفوذ داره نیست.

چه چیزهایی از مطالعه این سیستم یاد می‌گیریم؟

  1. مدیریت منابع محدود و هم‌روندی:‌ کارکرد اصلی این سیستم این بوده که به ۸۰-۹۰ نفر اولی که درخواست می‌دن نفری یه نوبت بده. این مسئله، چیزیه که همه سیستم‌های رزرو بلیط هواپیما و هتل و کنسرت و... باهاش روبه‌رو هستن. حتی در نگاه کلی‌تر، سیستم‌های بانکی و نظایر اون هم با موضوع مشابهی سروکار دارن (اینکه یه تراکنش بیش از یک بار پردازش نشه و/یا مجموع برداشت‌ها بیش از موجودی نشه). راه‌حل‌های شناخته‌شده‌ای هم داره. الآن امّا از یک طرف سیستم بر اساس ورود به صف نوبت‌ها رو نمی‌ده، بلکه براساس «هر کسی زودتر فرآیند رو تکمیل کنه» داره کار می‌کنه و در نتیجه ممکنه شما نوبتی آزاد رو انتخاب و فرآیند رو تکمیل کنی، ولی نوبت بهت نرسه! و از طرف دیگه، اگر حدس‌مون مبنی بر وجود Lost Update درست باشه، حتی ممکنه کسی دیرتر فرم رو تکمیل کنه ولی برنده‌ی نوبت بشه!
  2. کافی نبودن کنترل ورودی سمت کاربر: کاربر می‌تونه مستقیم API شما رو فراخوانی کنه و کنترل‌ها رو رد کنه. اینجا CAPTCHA فقط سمت کاربر داره چک می‌شه (که در رو برای ربات‌ها باز می‌گذاره). یا محدودیت‌های ورودی‌های فرم هم (مثل آدرس) به نظر فقط سمت کاربر اعمال می‌شن و توی API چک نمی‌شه. (توضیحات بیش‌تر در OWASP)
  3. مدیریت طول صف: وقتی کد یا لینک بعد از تاریخ انقضا به‌دست کاربر می‌رسه، یعنی طول صف بیش از زمان مورد انتظاره. طبیعتاً برای طراح این سیستم اصلاً کاربر اهمیتی نداشته، امّا اگر شما دارین سیستم مشابهی طراحی می‌کنین، باید این موضوع رو مانیتور کنین و در صورت رد شدن از آستانه، براش فکری بکنین: یا ورودی رو محدود کنین، یا سرعت پردازش رو زیاد کنین یا دست کم زمان انقضای کد/لینک رو.
  4. محدودیت روی نرخ درخواست‌ها: اگرچه محدودیت تعداد درخواست بر اساس شماره موبایل، جلوی بخشی از مشکل رو می‌گیره، امّا همونطور که بالاتر توضیح دادم، همچنان روزنه‌هایی رو باز می‌گذاره که می‌تونه منجر به DoS بشه. در این سیستم خاص، ممکنه انگیزه از اعمال نکردن محدودیت روی IP، جلوگیری از ایجاد مشکل برای افرادی باشه که هم‌زمان از یک نقطه (مثل کافی‌نت، یا خونه، یا حتی محل کار) درخواست می‌دن.
  5. استفاده نکردن از شناسه متوالی و/یا قابل حدس: ما اینجا تنها استفاده‌ای که از متوالی بودن کردیم، شناسایی نوبت‌های با شانس بیش‌تر و پتانسیل پریدن از یه مرحله بود؛ امّا در شرایط دیگه می‌تونه عواقب بدتری داشته باشه. (توضیحات بیش‌تر در OWASP)
  6. دریافت نکردن اطلاعات اضافی: به خصوص در این شرایط که هر روز خبر هک یکی از سامانه‌های دولتی بیرون میاد، نمی‌فهمم چرا باید این همه اطلاعات رو درحالی که بهش نیازی ندارن از کابر بگیرن؟ به خصوص تو همچین سیستمی که با استعلام سروکار داره، می‌تونه با داشتن کد ملی بقیه مشخصات رو از سیستمی مثل ثبت احوال بگیره.
  7. برنگردوندن اطلاعات اضافی به کاربر: چرا کاربر احراز هویت نشده، باید بتونه موجودی پنل پیامکی سرویس شما رو بدونه؟ هر اطلاعات اضافه‌ای که سمت کاربر می‌فرستین، می‌تونه یه سرنخ یا امکان جدید برای نفوذ به سیستم شما باشه.
  8. حذف سرویس و کدهای مرده: کدها و سرویس‌هایی که دیگه استفاده نمی‌شن، و احتمالاً کسی هم خیلی حواسش بهشون نیست، چرا باید در دسترس باشن؟ همین نوبت‌دهی در حالی که با خوش‌خیالی در ساعت‌های دیگه جلوی درخواست‌ها رو با خطای «نوبت‌دهی فعال نیست» یا «نوبتی وجود ندارد» گرفته بود، به خاطر بالا بودن سرویس سابق روی یه زیردامنه‌ی دیگه، دسترسی ارسال پیامک رو به افراد می‌داد. و این کار رو با نگه داشتن کدهای بی‌استفاده، ساده‌تر هم کرده بود.
  9. تجربه کاربری: ما از همچین سیستمی که کارکرد اصلی‌ش رو هم درست انجام نمیده، چنین انتظاری نداریم. حتی برعکس،‌ فکر می‌کنم هدف همین بود که پروسه مزخرف و سخت باشه و همین نقش فیلتر رو ایفا کنه. ولی اگر شما می‌خواین سیستم مشابهی طراحی کنین، به جای اینکه اطلاعات کاربر رو در انتهای فرآیند و هربار بپرسین، در ابتدا و ترجیحاً یک‌بار بپرسین (یا خیلی بهتر، از قبل ثبت نام کنین افراد رو). اطلاعاتی که از قبل از کاربر گرفتین رو دوباره درخواست نکنین (نه مثل اینجا که بعد از تایید باز شماره موبایل می‌گرفت). رنگ حالت‌های مختلف دکمه رو متمایز کنین (والا آدما ۲۰درصد روشن‌تر رو متوجه نمی‌شن). و...

شما فکر می‌کنین دیگه چه نکته‌ای میشه از این تجربه یاد گرفت؟


برنامه نویسیمهندسی نرم افزارامنیتconcurrency
سالک .[ ل ِ ] (ع ص ، اِ) مسافر و راه رونده. / a3dho3yn.ir
شاید از این پست‌ها خوشتان بیاید