آموزش ایجاد امنیت در ارتباط آنلاین + شرح چندین روش + سورس
خیلی وقت ها پیش می آید که ما می خواهیم اطلاعاتمان را از سرور بخوانیم و برای این کار یک یا چند API سمت سرور می نویسیم که با صدا زدن آنها اطلاعات را دریافت می کنیم.
در روشی که اکثر افراد تازه کار یا حتی متوسط انجام می دهند ، برنامه فقط API مورد نظر خودش را صدا میزند و اطلاعات را می خواند و این در حالی است ک اگر شخص دیگری از این API اطلاع داشته باشد می تواند به راحتی اطلاعات سمت سرو را بخواند.
مثال:
در این جا یک مثال خیلی ساده مطرح می کنم که ممکن است از نظر نیاز های یک پروژه خیلی کاستی داشته باشد. اما فقط می خواهیم بینیم چطور می توان یک امنیت خوب به وجود آورد.
فرض کنید شما یک برنامه Note ساده نوشته اید که قرار است هر شخصی که آن را نصب می کند بتواند با نصب این برنامه روی چند گوشی مختلف ، زمانی ک یک متن در یک گوشی اضافه کرد در سایر گوشی ها نیز این متن قابل دسترس باشد . برای این کار به صورت خیلی ساده ، فرض می کنیم یک API برای ارسال یادداشت جدید به سمت سرور و یک API برای دریافت اخرین یادداشت ها نوشته ایم. همچنین فرض کنیم هر کاربر یک ایمیل برای خود وارد کرده که ما بر اساس ایمیل آن شخص گوشی های موبایلش را همگام می کنیم.
در ادامه به روش های مختلف تامین این امنیت می پردازیم.
برای اینکه بتوانیم در مورد هر روش جداگانه صحبت کنیم ، آنها را در پست های جداگانه ارسال می کنم. لطفا در مورد هر کدام فقط زیر خودش کامنت کنید. لطفا تا حد ممکن پست نگذارید.
لطفا تا تکمیل شدن بحث پاسخی درج نکنید. (این مطلب کمی طولانی است و ممکن است چند روز طول بکشد، برای اطلاع از ادامه مبحث می توانید با کلیک روی دکمه زنگوله عضو شوید ) زمانی که مطلب کامل شد این سطر را پاک می کنم.
متشکرم
1 -روش بدون امنیت:
سمت سرور یک API تعریف می کنیم که دو پارامتر می گیرد. (ایمیل کاربر و شماره آخرین یادداشت دریافت شده) و سرور توسط یک Json تمام یادداشت های جدید را ارسال می کند. در این روش فقط کافی ست هکر آدرس API ما را بدست آورد
2- روش با امنیت پایین:
اینکه علاوه بر مواردی که در روش قبل وجود داشت یک کلید ثابت درون کد برنامه قرار دهیم به این شکل هر زمان که API را صدا می زنیم تا این کد را نفرستیم API جواب مناسبی نمی دهد. به این روش API Keyنیز می گویند. معمولا در پیاده سازی نقشه google map از آن استفاده کرده اید. اما این روش برای استفاده در اطلاعات محرمانه کاربرد ندارد. چون یک هکر می تواند به راحتی سورس کد شما را باز کند و این کلید را بدست آورد
3 - روش با امنیت متوسط ولی خطرناک :
به جای API Key ، از کاربر یک رمز بپرسیم و از آن برای هر شخص جداگانه استفاده کنیم. در این روش ما برای هر بار ارتباط به رمز کاربر نیاز داریم. پس یا باید هر بار رمز را از کاربر بپرسیم یا آن را در جایی ذخیره کینم و در دفعات بعد آن را ارسال کنیم
. ذخیره رمز در گوشی افراد کاری بسیار اشتباه است.چرا که ممکن است یک نرم افزار دیگر این رمز را بخواند. (در گوشی های روت شده که بسیار میسر خواهد بود) حالا فرض کنید یک هکر تصمیم بگیرد رمز کل کاربران برنامه شما را بدست آورد. کافی است با ترغیب کاربران به نصب یک برنامه دیگر ، رمز کلیه کاربران را پیدا کند و علاوه بر اطلاعات آنها رمز کاربران را نیز دارد که خود سایر ماجرا های مشکل سازی را می تواند ایجاد کند.
راه حل چیست ؟
امروز تقریبا اغلب سیستم های آنلاین از API یا سوکت استفاده می کنند که مطمئنا نیاز به تامین امنیت آن حیاتی است. راه کار مفید این کار معروف است به jwt یا Json Web Token که در صورت رعایت موارد کامل آن ، شما می توانید علاوه بر تامین نرم افزار ، چیزی شبیه به Session (نشست) که در طراحی وب سایت ها امری بسیار پر کاربرد است را به دنیای موبایل بیاورید.
روش jwt بسیار انعطاف پذیر است و شما را قادر می کند بتوانید بسیاری از عملیات مرتبط با امنیت را نیز همزمان پیاده کنید. مثلا تعیین سطح دسترسی ، همگام سازی مشخصات کاربر لاگین شده و ... . اخیرا شرکت Auth0 (تلفظ : آت زیرو) امکانات بسیار شگفت آوری را با استفاده از این روش پیاده کرده و کتابخانه های مربوط به تمام زبان های برنامه نویسی را برای سیستم خود پیاده کرده است. با سیستم این شرکت شما می توانید در عرض چند دقیقه امنیت را به نرم افزار خود اضافه کنید و از دنیای امکانات و گزارش هایی که سایت این شرکت به شما می دهد استفاده کنید. هم اکنون این سروریس تا سقف 7000 کاربر فعال در ماه به شما رایگان سرویس می دهد و بیش از آن باید پول بدهید. (که البته متاسفانه با IP های ایران مشکل دارد)
در ادامه به توضیح این مورد می پردازم.
JWT چیست ؟
در واقع jwt چیزی نیست جز یک کلید رندوم بین کلاینت و سرور. در تصویر زیر ابتدا مراحل ایجاد این کلید را می بینیم
ساختار JWT :
در تکنیک jwt ما یک کلید تبادل تولید می کنیم که برای ایجاد امنیت از آن استفاده می کنیم. به این کلید توکن (Token) می گوییم. درواقع توکن یک رشته است که از سه قسمت تشکیل شده. که هر قسمت از قسمت دیگر توسط یک نقطه جدا می شود. این سه قسمت عبارتند از:
- Header
Payload
Signature
Header
هدر خود از دو قسمت تشکیل شده. نوع توکن که درواقع کلمه jwt است و الگوریتم رمز نگاری که مثلا می تواند HMAC ، SHA256 , RSA و یا موارد دیگری باشد. مثال:
{
"alg": "HS256",
"typ": "JWT"
}
Payload
این بخش قسمت دوم توکن است که اطلاعات اصلی کلید را تشکیل می دهد. در این قسمت جزئیات امنیتی مورد نیازمان را اضافه می کنیم. به این جزئیات claims (مطالبه) نیز گفته می شود.
این جزئیات به دو سری عمومی و اختصاصی دسته بندی میشوند.
عمومی ها شامل کلید واژه های رزرو شده ای هستند بین جامعه طراحان jwt قرارداد شده. مثلا iss برای مشخص کردن نام تولید کننده توکن استفاده می شود یا exp برای مشخص کردن تاریخ انقضای این توکن بکار می رود.
خصوصی ها می تواند هر مقدار دلخواهی باشد که شما تعریف می کنید.مثلا شما می خواهید مشخص کنید که نام کاربری که لاگین کرده چیست می توانید یک عبارت مثل name تعریف کنید.
در این مثال نمونه یک payload مشاهده می کنید:
{
"iss": "scotch.io",
"exp": 1300819380,
"id": 54351,
"name": "Chris Sevilleja",
"admin": true
}
Signature
قسمت سوم که امضای توکن نام دارد جهت امن کردن این اطلاعات و رمزنگاری استفاده می شود.نکته اینکه الگوریتم رمز نگاری همان است که در type در Header مشخص شده بود. مثلا اگر ما بخواهیم از الگوریتم HMAC SHA256 استفاده کنیم با استفاده از یک تابع مثل تابع زیر مقدار امضا را بدست ی آوریم :
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
نکته مهمی که وجود دارد این است که در رمز نگاری یک رمز (secret) نیاز است که این رمز اولین بار توسط سرور و به صورت یک عدد دلخواه رندوم تولید و نگهداری می شود. این رمز در اختیار شخص دیگری قرار ندارد. بعدا در ادامه مطلب دلیل این کار را توضیح خواهم داد ولی فعلا به ادامه ماجرای تولید این توکن می پردازیم
خب حالا ما یک توکن سه بخشی داریم. برای تولید رشته نهایی تمام قسمت ها باید به صورت رشته Base64 تبدیل شده باشند. این توکن در نهایت چیزی شبیه این خواهد شد :
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
شما می توانید برای تست یک jwt آن را در این سایت وارد کنید.
چرا از jwt استفاده کنیم ؟
هدف از ایجاد jwt دو چیز است.
- امکان ایجاد تکنیک Login به صورت امن در سرویس های سمت کاربر (Client side)
- امکان تبادل اطلاعات محرمانه بین دو دستگاه.
همان طور که می دانید در روش طراحی وب سایت سمت سرور (Server side) یک فضای بسیار کاربردی به نام Session (نشست) در اختیار برنامه نویس قرار می گیرد که هرگاه کاربری لاگین می کند مشخصات او در این فضا ذخیره می شود و تا هنگامی که کاربر مرورگر خود را نبسته و یا تا مدت مشخصی که کاربر هیچ عملیاتی انجام ندهد این نشست همچنان معتبر خواهد بود و برنامه نویس با خیال آسوده می تواند اطلاعات محرمانه را به وی ارائه کند.
خب این فضای نشست یا همان Session سمت سرور قرار دارد و سرور می تواند بر اساس یک سری پارامتر (که اینجا مجال بحث در مورد آن نیست) به راحتی نشست ها را مدیریت کند. اما در تکنولوژی های سمت کاربر (Client side) دیگر امکان ایجاد نشست به شیوه سابق وجود ندارد چون اغلب اطلاعات سمت کاربر پردازش می شود. در این شیوه سرور باید یک سری API ایجاد کند و اطلاعات را به وسیله API ها به کاربر ارسال کند. در اینجاست که امنیت API ها مورد بحث قرار می گیرد.
تکنیک jwt آمده که این مشکل را حل کند. امروزه با توجه به گسترده شدن امکانات نرم افزاری در تولید اپلیکیشن های سمت کاربر و استفاده از API روش jwt بسیار مرسوم است و سورس های آن برای تقریبا تمام زبانهای برنامه نویسی در دسترس است.
در این تکنیک سرور یک رشته تولید می کند که شرح مختصری از آن در پست قبل آمد. زمانی که اولین بار App سمت کاربر درخواست لاگین می کند یک توکن تولید می شود. این توکن در پاسخ به درخواست App به آن ارسال می شود. از این پس هر زمان که App بخواهد یک Api را صدا بزند باید این توکن را هم همراه درخواست خود به سرور ارسال کند. سرور با بررسی توکن و اطمینان از صحیح بودن آن ، پاسخ درخواست جدید App داده می شود. اما اگر توکن معبر نباشد پاسخ عدم دسترسی ( خطای 403 یا هر پاسخ دیگری) به App برگردانده می شود.
در آینده در مورد اینکه چرا jwt امن است و چقدر امن است بحث خواهم کرد.
چرا JWT امن است ؟
همانطور که در پست های قبل آمد ، در تکنیک jwt پس از ارسال user/pass یک توکن از سرور دریافت می شود که App باید برای دسترسی به سایر Api ها به همراه درخواست خود ، هربار این توکن را نیز ارسال کند. نکته ای که اینجا وجود دارد این است که سرور زمانی که این توکن را برای اولین بار می سازد (وقتی App درخواست لاگین می کند) ، قسمت سوم توکن که همان Signature بود توسط یک رشته رندوم ایجاد و رمز نگاری می شود. و این رشته ی رندوم را هیچ کسی غیر از سرور نمی داند. به این ترتیب زمانی که از سمت کاربر یک درخواست می آید ، فقط سرور می تواند تشخیص دهد که Signature توکنی که از سمت کاربر آمده معتبر است یا نه ؟ و در صورتی که معتبر بود ، پاسخ را به آن درخواست ارائه می کند.
نکته دیگری که در این باره می توان مطرح کرد این است که هر توکن یک تاریخ انقضای مشخصی دارد. بنابر این سرور می تواند پس از گذشت مدت مشخصی ، از کاربر مجددا درخواست لاگین کند. این تاریخ به سیاست های طراحی نرم افزار بستگی دارد و از چند ساعت تا چند ماه معمولا متغیر است.
مزیت دیگری که در jwt قابل اعلام است ، ایجاد سطح دسترسی بر اساس کاربران متفاوت است. مثلا در قسمت Payload می توان سطح دسترسی یک کاربر را مشخص کرد. به این صورت درون نرم افزار سمت کاربر (APP) می توان برخی از گزینه ها یا منو ها را با توجه به سطح دسترسی ، محدود یا غیر فعال کرد.
پاسخگویی و مشاهده پاسخ های این سوال تنها برای اعضای ویژه سایت امکان پذیر است .
چنانچه تمایل دارید به همه بخش ها دسترسی داشته باشید میتوانید از این بخش لایسنس این آموزش را خریداری نمایید .