تصور کنید که یک اپلیکیشن اندروید توسعه دادهاید که با استفاده از وب سرویسهایی که خودتون براش نوشتید، سرویسی به کاربر ارائه میده. برای راحتی کار بیایید سناریوی زیر رو تصور کنیم:
یک اپلیکیشن فروشگاه آنلاین نوشتید که از یک وبسرویس استفاده میکنه تا تمام دیتای لازم برای نمایش محصولات، ثبتنام و ورود کاربر، خرید محصول و … رو از سرور بگیره. خب این حتی اگر تنها راه نباشه، قطعا منطقیترین راهه. حالا تصور کنید که من همون لحظهای که در حال وارد شدن به حساب کاربریام از طریق اپلیکیشن روی موبایلم هستم، یه آدم خبیث (که لزومی نداره آدم خاص و خیلی با سوادی باشه. تنها کافیه بدونه wireshark چیه) که به همون شبکهای که من بهش وصلم اتصال داره، خیلی راحت packet sniffing میکنه و تمام دیتایی که من برای ورود به اپلیکیشن استفاده کردم رو میدزده. نتیجه؟ از این به بعد خیلی راحت میتونه وارد حساب کاربری من بشه، از اعتبارم استفاده کنه و یا هر کار خبیثانه دیگهای رو انجام بده.
تازه این یه سناریو ساده بود. برای سناریو پیچیدهتر اون cracker خبیث میتونه کارهای پیچیدهتری با اطلاعاتی که از من دزدیده انجام بده.
خب این وسط مسئول این دزدی رخ داده کیه؟ قطعا توسعهدهندهی این اپلیکیشن هست که به جای رمزنگاری دادههای کاربر با یک روش مطمئن، اونا رو به صورت plain text ارسال کرده.
برای رفع این مشکل چندین راه حل نامطمئن و یک راهحل کاملا مطمئن وجود داره. راه حلهای نامطمئن استفاده از یکی از الگوریتمهای رمزنگاری متقارن هست که در اون کلید رمزنگاری و رمزگشایی یکیه. اما حداقل برای اپلیکیشنهای اندروید با اطمینان میگم که این اصلا روش درستی نیست. چون در این روش شما مجبورید کلید رو از پیش تعریف کنید و در داخل اپلیکشن قرار بدید. و از اونجایی که decompile کردن اپلیکیشن اندرویدی اصلا کار سختی نیست، cracker میتونه خیلی راحت کلید رو به دست بیاره و چون کلید برای تمام کاربران یکسانه، ازش برای رمزگشایی پکتهای sniff شده تمام کاربران استفاده کنه. البته تو روشهایی میشه کلید رو با استفاده از دیتای منحصر به فرد کاربر مثل IMEI گوشیش ساخت. تا کلید هر کاربر منحصر به فرد باشه. اما این روش هم قابل اطمینان نیست چون حداقل یکبار باید این رمز ساخته شده رو (به صورت plain text) به سرور ارسال کنیم تا سرور بفهمه که باید ارتباطاتش با این کاربر رو با چه کلیدی رمزنگاری و رمزگشایی کنه. و همین یکبار کافیه تا cracker کلید رو به دست بیاره و از این به بعد تمام ارتباطات شما رو رمزگشایی کنه.
خب تا اینجا فهمیدیم صرفا استفاده از رمزنگاری متقارن حلکنندهی مشکل ما نیست. رمزنگاری نامتقارن (یا همون رمزنگاری کلید عمومی) هم که کلا برای سناریوهای متفاوتی استفاده میشه و به تنهایی خیلی به کار نمیاد. پس راه حل چیه؟
بهترین راه حل استفاده از ترکیب این دو در روشی به نام “دیفی-هلمن” است که حداقل تا به امروز هیچ کسی تو دنیا موفق به شکوندنش نشده. دیفی-هلمن یک پروتکل برای تبادل کلید است که توسط اون (با استفاده از برخی روابط ریاضی) طرفین رمزنگاری (در اینجا سرور و اپلیکشن) هر کدام بخشی از کلید رو میسازند و از قرار دادن این بخشها کنار هم کلید کامل ساخته میشه. الگوریتم این روش کمی پیچیدگی ریاضی داره اما اگر علاقهمند هستید حتما توصیه میکنم نگاهی بهش بندازید تا از جذابیت علم ریاضی باخبر شید! و شاید جالب باشه بدونید این روش دقیقا همون روشیه که پیامرسان Telegram ازش برای رمزنگاری چتهای شما استفاده میکنه.
در حال حاضر یکی از روشهای پیادهسازی دیفی-هلمن استفاده از رمزنگاری نامتقارن RSA برای ساختن کلید بین اپلیکیشن و سرور، و سپس از استفاده از روش متقارن AES برای رمزنگاری ارتباطات بین سرور و اپلیکیشن با استفاده از کلید ساختهشده است. طبیعتا این روش باید هم در اپلیکیشن و هم در برنامه تحت سرور اجرا بشه تا طرفین بتونند با هم ارتباط داشته باشند.
توضیح پیادهسازی این روش خارج از حوصلهی این نوشته است. اما اگر عمری بود و زمان اجازه داد، سعی میکنم تو چند قسمت پیادهسازیش کنم و توضیح بدم و نمونه کدها رو قرار بدم.
خیلی خوب بود
راضیم ازت 🙂
خب دیگه چی بهتر از این ؟:)
برای پیاده سازی تنها یک راه مطمئن وجود نداره بلکه چندین راه وجود داره! کلا پروتکل دیفی-هلمن همانطور که اشاره کردین برای تبادل کلید هستش ! نه رمزنگاری! متون رمزنگاری شده توسط الگوریتم های متقارن ( AES,IDEA,) ساخته میشن و بعد از طی چندین پروسس یک پکیچ تشکیل داره میشه که شامل پیام رمزنگاری شده ، session key، messege digist ، … سپس جهت اطمینان از اینکه کلید در جالت امن انتقال میشه از RSA برای تبادل استفاده میشه . در اینجا ممکنه این تبادل فقط بین دو کلاینت باشه و سرور تداخلی نداشته باشه .
در ضمن اگر نفر سومی مابین ارتباط نفر اول و دوم در DH قرار بگیره ، میتونه بدون اینکه شناسایی بشه به تبادل اطلاعات دست بزنه! چطور؟ کافیه اول پیام هر کدوم رو با کلید رمز خودش بخونه بعد با کلید رمز طرف طرف مقابل پیام رو رمز نگاری کنه و بفرسته ! اسم این متد مشهوره MITM!
واسه همین یه مکانیزم به این پروتکل باید اضافه بشه که بتونه طرفین مقابل رو شناسایی کنه ! بالا کمی توضیح دادم.
تشکر از مطالبتون.
حق با شماست. تو دنیای کامپیوتر هیچ راهی تنها راه نیست و بهتر بود مینوشتم تنها راهی که در حال حاضر من بلدم.
چیزی که گفتید درسته. اگر از این روش همینجوری که من گفتم استفاده شده MITM ممکنه رخ بده. اما خب این هم با استفاده از یک روش رمزنگاری نامتقارن مثل RSA قابل حله. طوری که وقتی ماشین اول دیتای لازم برای ساخت کلید رو به ماشین دوم میده،اونا رو با یک کلید عمومی رمز میکنه و ماشین دوم که سروره با کلید خصوصیش رمز رو باز میکنه.
اگر سرویسی که میسازید رو در CA ها ثبت کنید دیگه مشکلی نداره چون شما یک گواهینامه دیجیتال دارید که یه نفر معتبرتر پای اون رو امضاء کرده و بنابراین اگر کسی بخواد مردی-در-میان بزنه دستش رو میشه…
این چیزی که گفتم برای وقتیه که شما دارید از یه برنامهی تحت وب استفاده میکنید و از قبل هیچ تبادلی با هم نداشتید در صورتی که تمرکز آرش روی اپلیکشنهای اندرویدیه که یعنی یه نفر از قبل برنامهی شما رو دانلود کرده و میخواد از طریق اون به وب سرور وصل بشه. بنابراین اصلا نیازی به تایید CA وجود نداره چون شما از قبل کلید عمومیتون رو داخل برنامهای که نوشتید قرار دادید.
خیلی جالب بود، مخصوصا بعدش که رفتم راجع بهش بیشر خوندم بیشتر جالب شد.
فقط بازم نیاز به authentication هست تا کسی نیاد وسط.
و البته شکسته نشدنشم هم خیلی بستگی داره به انتخاب پارامتر ها و …
۱. روش دیفیهلمن برای توافق و ساخت یک کلید به صورت اشتراکی بهکار میره و در تولید کلید هر دو طرف نقش دارن. روش استفاده از تابع RSA برای انتقال کلید (Key exchange) به کار میره به این صورت که یکی از طرفین کلید رو تولید میکنه و به کمک RSA کلید رو به صورت امن به طرف مقابل منتقل میکنه.
۲. کد IMEI آنتروپی کافی نداره، قابل پیشبینی هست و ثابته، کلیدی که بر اساس IMEI یا هر کد مشابه دیگهای ساخته بشه ارزش امنیتی نداره
۳. تلگرام امن نیست! ادعایی که تلگرام دربارهی امنیت داره دربارهی یک حملهی غیر فعال هست و در مقابل Active attack آسیب پذیره. خیلی راحت میشه پروتکلهای عمدا افتضاحی و نا امنی طراحی کرد که در مقابل حملات غیر active امن باشن.
۴. مبانی ریاضی DH خیلی سخت نیستند، من اینجا مینویسم اگر خواستید داخل متن هم گپی کنید.
در روش DH طرفین سعی میکنند سر یک کلید رمزنگاری مشترک به توافق برسند به طوری که اگر کسی ارتباط بین این دو طرف رو بتونه شنود کنه نتونه کلید رو باز سازی کنه.
۱. یکی از طرفین یک عدد اول بزرگ (q) تولید میکنه و یک عدد g < q رو انتخاب میکنه. این g باید یک خاصیت سادهای داشته باشه که برای اینکه چند تعریف ریاضی و نظریه اعدادی داره اینجا نمینویسم که متن روون باشه. ولی در کل بدونید که انتخاب رندوم یک عدد اول بزرگ خیلی راحته و چون تعداد اعداد ۱ تا q هم زیادن احتمال اینکه اگر یک عدد رندومی رو تو این بازه انتخاب کنیم مناسب انتخاب شدن به عنوان g باشه زیاده. کلا تولید q و g خیلی سخت نیست.
۲. این طرف دو عدد q و g رو به صورت plain text برای طرف مقابل میفرسته. تا اینجا:
اطلاعات طرف اول (الف): q و g
اطلاعات طرف دوم (ب): q و g
اطلاعات متخاصم که خط رو شنود میکنه: q و g
۳. حالا هر یک از طرفین یک عدد رندوم دلخواهی(فرض کنید اسمشون رو بزاریم Xa و Xb) رو انتخاب میکنن. طرف (الف) عدد g رو به توان Xa میرسونه و با قیماندهی مقدار به دست اومده نسبت به q رو برای طرف دوم میفرسته. طرف دوم هم همینکار رو با Xb انجام میده
تا اینجا:
اطلاعات طرف اول (الف): q و g و Xa و g^Xa mod q و g^Xb mod q
اطلاعات طرف دوم (ب): q و g و Xb و g^Xb mod q و g^Xa mod q
اطلاعات متخاصم که خط رو شنود میکنه: q و g و g^Xa mod q و g^Xb mod q
۴. طرف اول عددی که از طرف دوم دریافت کرده رو به توان a میرسونه و نسبت به q باقیمانده میگیره، طرف دوم هم عددی که از اولی گرفته رو به توان b میرسونه و نسبت به q باقیمانده میگیره. توی ریاضیات دوران راهنمایی خوندیم که:
(x^a)^b = (x^b)^a = x^(a*b) هست، این روابط بعد از باقیمانده گرفتن نسبت به q هم صادق هستند. پس الان اگر دقت کنیم میبینیم که طرفین به یک مقدار مشترک که همون g به توان Xa*Xb هست رسیدن و میتونن از این مقدار به عنوان کلید استفاده کنن.
۵. الان فرد متخاصم (شنودگر) این اطلاعات رو داره: q و g و g^Xa mod q و g^Xb mod q ولی برای به دست اوردن کلید مشترک بین این دو طرف خود مقدار Xa یا Xb رو لازم داره. توی دبیرستان خوندیم که اگر از g^x در مبنای g لگاریتم بگیریم مقدار g به دست میاد پس الان متخاصم که هم g رو میدونه هم g به توان Xa و هم g به توان Xb پس چرا نمیتونه مقدار Xa و Xb رو راحت با لگاریتم گرفتن به دست بیاره؟ نکتهی ماجرا توی باقیمانده نسبت به q گرفتنه هست. این عمل سادهی باقیمانده گیری مسئلهی لگاریتم گیری رو تبدیل به لگاریتم گیری گسسته (DLog) میکنه که کلا با لگاریتم گیری اعشاری عادی تفاوت داره و جزء مسائل NP هست. یعنی با یک کامپیوتر هم ممکنه سالها طول بکشته تا لگاریتم گسستهی یک عدد بزرگ در مبنای یک عدد بزرگ دیگه محاسبه شه. حل مسائل NP انقدر سخت هست که در عمل اونها رو غیر ممکن فرض میکنند و بر اساس فرض اینکه این مسائل قابل حل نیستند Trapdoor functionها و الگوریتمهای رمزنگاریای تعریف میشن (مثل همین DH یا RSA) که امنیت رو برای ما فراهم میکنن
سلام
کاش واسه پیاده سازی php یه کتابخونه یا کلاسی چیزی معرفی می کردید!
لطفا رمزنگاری کد imei رو بذارین لطفا و خواهشا و البته حتما.
بسیااااار مطلب مفید و عالی ای بود…ممنون از شما 🙂
از دوست عزیز محمدجعفر هم به خاطر کامنت خوبشون تشکر می کنم
سلام من یه تحقیق راجب بررسی الگوریتم های رمزنگاری در بستر اندروید میخواستم از کجا میتونم پیدا کنم؟ خیلی واجبه میشه بهم کمک کنید
سلام طبق این مقاله روشی ک فرمودید هم زیاد امن نیست
https://news.asis.io/content/نقطهضعف-استفاده-از-اعداد-اول-در-الگوریتمهایی-مانند-دیفی-هلمن