یه هک باحال روی سورس فلسک
قبلا هم در مورد هک و تغییر در سورس فلسک نوشته بودم.
خوب، دفعه قبلی کاری که کردم خیلی استاندارد نبود با این حال، عبرت نگرفتم و اینبار هم وقتی توی محل کارم حساسیت جدیی ایجاد شد که کاری رو انجام بدیم، تصمیم گرفتم جای گوش کردن به حرف core-developer ها و خلاصه دولوپرهای حرفهای فلسک که میگفتن این کار رو نکن، یا نمیشه یا خوب نیست که انجامش بدم، به صورت ازمایشی کار رو انجام بدم و چون از نتیجه خیلی راضی بودم، فک کردم چرا که نه و فرستادیم روی پروداکشن و تایید شد و به اینجایی رسید که الان بیام براتون یه مثال از نحوه انجامش بزنم! :)
تنظیمات فلسک، یا خیلی از اپلیکیشن های پایتونی(شاید بقیه زبانها هم؟) به این صورت هستن که توسط اپ خونده میشن، اپ بالا میاد و بعدا اگر نیاز باشه دستکاری بشن، باید اونها رو ریاستارت کنیم. فلسک لیست بلندبالایی از این تنظیمات رو داره و هر اکستنشن یا پلاگینی که روش نصب میکنی، خواه ناخواه یه سری کانفیگ بهش اضافه میکنه.
نیاز ما، این بود که بتونیم در حال اجرا، بدون ریستارت شدن اپ، این مقادیر رو عوض کنیم!
بذارید با یه مثال بریم جلو. PERMANENT_SESSION_LIFETIME
یکی از مقادیری هست که در زمان ساختن اپلیکیشن مقداری رو براش تعیین میکنیم و فلسک باهاش بالا میاد. این متغییر، طول عمر سشنها رو تعیین میکنه و در صورتی که کاربر، برای مدت زمان معینی(مشخص شده توسط این متغییر) هیچ کاری نکنه(ریکوستی ارسال و دریافت نکنه) سشنش پاک میشه و از سایت لاگاوت میشه.
فرض کنید نیاز دارید که کاربر شما، در پنل ادمین برای مثال، بتونه در حال اجرا این مقدار رو عوض بکنه. خوب، قاعدتا نیاز هست تا اپلیکیشن ریستارت بشه.در کاربردی که ما برای اپلیکیشنمون داشتیم، نیاز بود که در هنگام تغییر این تنظیمات، اپلیکیشن فلسک ریستارت نشه و خوب، با توجه به نحوه کار کرد فلسک، یه جورایی این قضیه غیر ممکن به نظر میرسید.
تحقیق
اولین مرحله برای هک کردن یه چیزی(هک= تغییر در یک چیز، تا کاربریی که براش در نظر گرفته شده رو دنبال نکنه و طبق خواستهٔ ما انجام وظیفه کنه!)، باید در موردش اطلاعات کسب کنیم و بفهمیم که چطوری کار میکنه.
رای اینکار، در یک اپلیکیشن اوپن سورس، کافیه سورس رو باز کنین و بخونید که چطوری کار میکنه. این یه کانفیگ هست، پس من انتظار دارم که داخل کلاس Flask اثری ازش وجود داشته باشه. دلیل این انتظار، به صورت منطقی این هست که من برای ساختن یه اپلیکیشن فلسک، به این صورت عمل میکنم:
app = Flask(name)
app.config.from_object(config_file)
خوب، همینجور که میبینید، داریم یکسری متغییر و متد از داخل کلاس Flask رو دستکاری میکنیم.
انتظارم درست هست. کد رو در سورس فلسک به راحتی پیدا میکنم و اتفاقا داخل کلاس Flask هم هستش.
#: A :class:`~datetime.timedelta` which is used to set the expiration
#: date of a permanent session. The default is 31 days which makes a
#: permanent session survive for roughly one month.
#:
#: This attribute can also be configured from the config with the
#: ``PERMANENT_SESSION_LIFETIME`` configuration key. Defaults to
#: ``timedelta(days=31)``
permanent_session_lifetime = ConfigAttribute('PERMANENT_SESSION_LIFETIME', get_converter=_make_timedelta)
خودش، و کامنتهاش به سادگی و زیبایی پیدا میشن. خیلی خوب شد. پس یه متغییر داریم که داره از اون کلید یا متغییر استفاده میکنه. ولی این متغییره خودش کجا داره استفاده میشه؟ توی سورسفایلهای فلسک، یه فایل به نام session.py هست که خوب، قائدتا بعد از فایل موجود، دومین کاندیدا برای بررسی هستش و باید بگم که بینگو! :)
def get_expiration_time(self, app, session):
"""A helper method that returns an expiration date for the session
or ``None`` if the session is linked to the browser session. The
default implementation returns now + the permanent session
lifetime configured on the application.
"""
if session.permanent: return datetime.utcnow() + app.permanent_session_lifetime
خیلی عالیه. مقدار مربوطه، هر بار و در هر ریکوست خونده میشه، محاسباتی روش صورت میگیره تا معلوم بشه که سشن کی باید پاک بشه. خیلی راحت و ساده. تنها کاری که نیازه، این هست که متغییر permanent_session_lifetime رو از ابجکت app مقدار دهی درست کنم.
چند هک و تریک کوچیک و بزرگ و رویا پردازی به سرم میزنه! ولی خوب، پایتون یه زبان شیگراست و شیگرایی دوست ماست! پس چرا که نه؟
class New_Flask(Flask):
permanent_session_lifetime = datetime.timedelta(minutes=3)
خوب، حالا داخل فایل application.py که به اصطلاح Factory اپلیکیشن من هست(اگر نمیدونین فکتوری چی هست، اخر این پست براتون لینکشرو میذارم) حالا باید فقط یک کلمه رو عوض کنم:
app = Flask(__name__)
# changes to
app = New_Flask(__name__)
همه چیز خیلی راحت بود. اپلیکیشن رو اجرا میکنم، کار میکنه و همه چیز سر جاشه...(البته من برای اینکه بفهمم که باید timedelta بهش بدم مجبور شدم قبل از درست خوندن داکیومنت و کامنتهای کد، چند چیز مختلف رو تست کنم که اینجا سانسور شده اون تلاش :)
خوب، حالا سوال این هستش که چطوری میتونم مقدار رو از داخل route ها عوض کنم؟
من یه route جدید برای تغییر مقدار sesstion_lifetime مینویسم، مقدار رو از کاربر دریافت میکنم و اون رو در متغییر timeout ذخیره میکنم.
timeout = request.form.get("session_lifetime")
حالا، کافیه دومین جادوی شیگرایی رو به کار بگیرم:
current_app.permanent_session_lifetime = datetime.timedelta(minutes=timeout)
چند تست و همه چیز درست و تمیز کار میکنه.
نکتهای که باید بهش توجه بکنید این هستش که من این کدها رو الان، اینجا و برای این مطلب نوشتم، و حقیقتا به صورت ذهنی دارم کدها رو مینویسم(کدهای مربوط به فلسک رو هم از گیتهاب کپی کردم) به چند دلیل:
۱- نمیتونم کدی که توی شرکت نوشتیم رو به اشتراک بگذارم، حتی در حد چند خط
۲- عمومیت کد در صورت نوشتن کد واقعی از بین میره
۳- در صورتی که ولیدیشنها و اکسپشنهندلینگها و شرط و شروط لازم برای بر نخوردن به مشکل رو داخل کنیم، کلی کد باید اینجا مینوشتم.
بنابراین امیدوارم که ایدهٔ کلی رو گرفته باشید از اینکه چطوری میشه خیلی راحت و ساده، اپلیکیشنهای مختلف رو هک کرد، یا به قولی جوری دستکاریشون کرد که کاری که براش ساخته نشدن یا انجام نمیدن رو خیلی تمیز و راحت انجام بدن.
از اونجایی که قبل از انجام این حرکت کلی سرچ کردم و کسی چیزی ننوشته بود، این مطلب رو در اولین فرصت به زبان انگلیسی مینویسم و میذارم روی وبلاگ انگلیسی زبانم که بیرون از ایران هم اگر کسی نیاز داشت، بتونه استفاده بکنه.
در مورد اپلیکیشن فکتوری، میتونید در یوتوب| اپارات یا تخته سفید بیشتر ببینید!
- شنبه, ۲۵ آذر ۱۳۹۶، ۰۸:۱۰ ب.ظ