آموزش OAuth 2

OAuth 2احتمالا دیده‌اید که در خیلی از وب‌سایت‌ها امکان لاگین با حساب گوگل وجود دارد. در این مطلب می‌خواهیم بررسی کنیم که وقتی با گوگل در یک وب‌سایت لاگین می‌کنید در پشت پرده چه اتفاقی رخ می‌دهد. این مطلب برای برنامه نویس ها و افرادی که علاقه دارند جزئیات OAuth رو بدونن کاربرد داره. دونستن عملکرد وب و پروتکل http هم لازم هست برای درک مطلب.تاریخچه و طرح مسئلهدر سال ۲۰۱۰، OAuth نسخه یک معرفی شد. دو سال بعد به دلیل مشکلات امنیتی آن، OAuth2 جایگزین OAuth1 شد.حال سناریویی را بررسی می‌کنیم تا درک کنیم که قبل از OAuth فرایند به چه صورت بوده و OAuth چگونه مسئله را حل کرده است.طرح مسئلهفرض کنید یک سرویس ابری اشتراک عکس وجود دارد که می‌توانیم عکس‌هایمان را بر روی آن ذخیره و مدیریت کنیم. در پروتکل OAuth به این سرویس، Resource Server گفته می‌شود. منابع، که در اینجا همان عکس‌ها می‌باشند، بر روی این سرور ذخیره و مدیریت می‌شوند.سرویس مذکور ابتدا کاربر را احراز هویت کرده و سپس به او اجازه مدیریت عکس‌ها را می‌دهد. در OAuth به کاربران مالک منبع یا Resource Owner گفته می‌شود.تا اینجا با دو موجودیت پروتکل یعنی resource server و resource owner آشنا شدیم.حال فرض کنیم یک سرویس پرینت عکس وجود دارد که یک شرکت دیگر آن را تولید کرده است. مسئله این است که کاربر (Resource Owner) می خواهد به سرویس پرینت دسترسی بدهد، به طوری که بتواند عکس‌های او را از سرویس اشتراک عکس دریافت کرده و سپس آن‌ها را پرینت بگیرد. این نکته رو هم بگم که در ادبیات OAuth، به سرویس پرینت که مثال زدیم، Client گفته می‌شود. پس تا اینجا به سرویس اشتراک عکس، Resource Server گفتیم؛ سرویس پرینت را Client نامیدیم و به کاربر واژه Resource Owner را نسبت دادیم. به طور مکرر از این واژه ها در متن استفاده شده.اولین راهکاری که برای حل سناریو به ذهن می‌رسد این است که کاربر، نام کاربری و کلمه عبور خود را در اختیار سرویس پرینت عکس قرار دهد. بنابراین سرویس پرینت خواهد توانست تا از طرف کاربر روی Resource Serverلاگین نموده و عکس‌ها را دریافت کند.این روش مشکلاتی دارد:وقتی نام کاربری و کلمه عبور به کلاینت داده شود، در واقع همه دسترسی‌ها در اختیار آن سرویس خواهد بود. لذا هر کاری که کاربر می‌تواند روی Resource Server انجام دهد، توسط کلاینت نیز قابل انجام خواهد بود. به طور مثال کلاینت می‌تواند عکس‌های کاربر را حذف کند.اگر کلاینت روزی توسط هکرها مورد نفوذ قرار گیرد، احتمال افشای نام کاربری و کلمه عبور کاربر وجود خواهد داشت. اگر روزی کاربر تصمیم بگیرد که دسترسی به کلاینت را قطع نماید، مجبور است نام کاربری و کلمه عبور خود را تغییر دهد. در این صورت همه کلاینت های مشابه از کار خواهند افتاد و مجددا باید نام کاربری و کلمه عبور بر روی همه آنها تنظیم شود.به طور کلی از نظر امنیتی صحیح نیست که نام کاربری و کلمه عبور (credential) در اختیار غیر قرار گیرد. در نتیجه این روش منتفی خواهد بود.حال به بررسی راهکار OAuth در این مسئله می‌پردازیم.همانطور که در شکل قابل ملاحظه است، در OAuth یک موجودیت جدید به نام Authorization Server اضافه شده است. به طور مثال، گوگل می‌تواند این نقش را داشته باشد. این سرور کار مدیریت و احراز هویت کاربران را انجام می‌دهد. وظیفه دیگر این سرور این است که پس از کسب اجازه از کاربر، برای کلاینت‌ها توکن دسترسی یا access token صادر نماید.OAuth کامپوننت هایبرای اینکه کلاینت بتواند از Resource Server عکس را دریافت کند، باید access token معتبر ارائه دهد. اکسس توکن را authorization server تولید می‌کند. اما با چه شرایطی؟ به روشی مالک منبع یا کاربر باید اجازه دهد که توکن برای کلاینت صادر شود.فرایند کلی OAuthProtocol Flowدر شکل فوق جریان یا flow کلی پروتکل OAuth ارائه شده است. در مرحله اول کلاینت می‌بایست با روشی اجازه Resource Owner را بگیرد. به این اجازه Authorization Grant گفته می‌شود.اگر Resource Owner رضایت داشت به کلاینت اجازه یا Grant را می‌دهد. کلاینت این authorization grant را به authorization server ارائه داده و اکسس توکن دریافت می‌کند. سپس کلاینت با ارائه اکسس توکن به ریسورس سرور، به منابع دسترسی پیدا خواهد کرد.همانطور که توضیح داده شد، در OAuth دیگر Resource Owner پسورد خود را در اختیار کلاینت قرار نمی‌دهد. بلکه به او یک Authorization Grant می‌دهد.نکته‌ مثبتی که در اینجا قابل ذکر است، این است که این امکان وجود دارد که مالک منبع در grant مشخص کند که کلاینت به چه چیزهایی دسترسی داشته باشد. در واقع scope اکسس توکن قابل تعیین است. Resource Server تنها اجازه دسترسی به Scope های موجود در اکسس توکن را خواهد داد و نه بیشتر. به طور مثال مالک منبع میتونه فقط دسترسی خواندن (مثلا read scope) به کلاینت بدهد؛ لذا کلاینت با آن اکسس توکن فقط می تواند عکس ها را بخواند و اجازه ویرایش و حذف نخواهد داشت.انواع Grant گفتیم که کلاینت باید به روشی از مالک منبع اجازه (grant) بگیرد. اما نگفتیم چگونه! در ادامه به انواع مختلف Grant در OAuth می‌پردازیم. در OAuth چهار نوع Grant تعریف شده است. لذا کلاینت به چهار روش مختلف می‌تواند از مالک منبع، اجازه کسب نماید.نوع اول: Authorization Code Gr‌‌antدر این نوع Grant، کلاینت با وساطت Authorization Server از مالک منبع اجازه را می‌گیرد. به این صورت که ابتدا کلاینت مالک منبع را به authorization server هدایت (redirect) می‌کند؛ در authorization server، مالک منبع ابتدا احراز هویت شده و سپس اجازه می‌دهد که کلاینت به ریسورس‌ها دسترسی داشته باشد. پس از آن Authorization Server یک کد (Authorization Code) به کلاینت ارائه می‌دهد. کلاینت با آن کد می‌تواند از Authorization Server اکسس توکن را دریافت نماید. این grant امن‌ترین grant در OAuth بوده و توصیه شده است که در صورت محیا بودن شرایط، از آن استفاده شود.نوع دوم: Implicit Grantاین نوع Grant بسیار مشابه نوع اول است، با این تفاوت که به جای ارسال کد به کلاینت، به طور مستقیم اکسس توکن در اختیار کلاینت قرار داده می‌شود. امنیت این روش پایین تر بوده و در سناریوهای خاصی استفاده می‌شود. در ادامه بیشتر در مورد این Grant توضیح داده خواهد شد.نوع سوم: Resource Owner Password Grantاین Grant شبیه روش ارائه شده در ابتدای مطلب (قبل OAuth) است. به این صورت که کلاینت نام کاربری و کلمه عبور مالک منبع را گرفته و با آن از authorization server اکسس توکن دریافت می‌کند. در واقع مالک منبع با ارائه نام کاربری و کلمه عبور خود به کلاینت، اجازه خود را اعلام می‌نماید.نوع چهارم: Client Credentials Grantدر این نوع Grant مالک منبع وجود ندارد و خود کلاینت در واقع نقش مالک منبع را دارد. لذا کلاینت با نام کاربری و کلمه عبور خود، اکسس توکن را دریافت می‌کند.لازم به ذکر است که grant ها قابل توسعه یا extend هست. یعنی می‌توان OAuthرا مبنا قرار داده و Grant های جدید به آن اضافه نمود. به عنوان مثال پروتکل‌های openid connect (OIDC) یا User Managerd Access (UMA)، در واقع یک extension بر روی OAuth می‌باشند.در ادامه با جزئیات بیشتر به موضوع Grant ها پرداخته خواهد شد. پیش از آن لازم است انواع کلاینت‌های OAuthرا بشناسیم.انواع کلاینت ها در OAuthکلاینت‌های OAuth به دو نوع Confidential و Publicتقسیم می‌شوند.کلاینت‌های Confidential: امکان ذخیره امن نام کاربری و کلمه عبور خود را دارند. به عنوان مثال اپلیکیشن تحت وب سمت سرور که می‌تواند Credentials را به صورت امن روی سرور ذخیره کند. به نحوی که امکان دسترسی غیرمجاز به آن وجود نداشته باشد.کلاینت‌های Public: امکان ذخیره امن Credentials خود را ندارند. مانند اپلیکیشن‌هایی که به صورت کامل سمت مرورگر اجرا می‌شوند (مثل فریمورک‌های جاوا اسکریپتی، انگولار، ری اکت و ...) یا اپلیکیشن‌های موبایلی. این نوع کلاینت‌ها از آنجایی که در دستگاه کاربر اجرا می‌شوند، عملاً امکان دسترسی به تمامی داده‌های آن‌ها سمت کاربر وجود دارد و قادر به ذخیره امن پسورد نخواهند بود.بررسی دقیق تر Grant هایک: Authorization Code Grantمراحل کلی اخذ اجازه از کاربر به روش Authorization Code در شکل زیر نمایش داده شده است.Authorization Code Grantدر ادامه درخواست‌ و پاسخ‌های HTTP که بین مرورگر کاربر، کلاینت و authorization server مبادله می‌شود به تفصیل شرح داده شده است. طی 9 مرحله زیر اکسس توکن در اختیار کلاینت قرار داده شده و با آن می‌تواند به سرویس های resource serverدسترسی پیدا کند.در درخواست‌ها و پاسخ‌های HTTP که در ادامه آمده است، رشته‌های طولانی و موارد غیر مهم با "..." خلاصه شده است.مرحله یک: فرض کنید مالک منبع پشت لپ تاپ خود نشسته است و از طریق یک مرورگر مانند گوگل کروم یا فایرفاکس (User Agent) وب سایت print-service.com (کلاینت) را باز می‌نماید. لذا یک درخواست HTTP مشابه زیر توسط مرورگر ایجاد شده و به کلاینت ارسال می‌شود.GET /print/2 HTTP/1.1 Host: print-service.com …مرحله دو: کلاینت درخواست را بررسی نموده و متوجه می‌شود که اکسس توکن معتبری از کاربر ندارد. لذا با ارسال یک http response با کد 301، مرورگر کاربر را به Authorization Serviceهدایت می‌کند.HTTP/1.1 302 Location:http://auth-server.com/auth?response_type=code&client_id=print-service&scope=read&redirect_uri=http://print-service.com/login/OAuth2/code/testدر این ریدایرکت پارامترهای زیر به Authorization Server ارسال می‌شود:پارامتر response_type: برای تعیین نوع Grant به کار می رود. عبارت code به معنای Authorization Code Grant می باشد.پارامتر client_id: برای این که Authorization Server متوجه شود که درخواست از کدام کلاینت آمده است. لازم به ذکر هست که کلاینت باید از قبل در Authorization Server ثبت نام کرده باشد و client_id منحصر بفرد گرفته باشد.پارامتر redirect_uri:آدرسی است که بعد از احراز هویت و کسب اجازه از کاربر، Authorization Server مرورگر کاربر را به آن ریدایرکت خواهد نمود. این پارامتر می‌بایست از قبل در Authorization Server برای کلاینت ثبت شده باشد.پارامتر scope:همانطور که پیش‌تر گفته شد، پارامتر scope به منظور تعیین محدوده دسترسی است. در اینجا کلاینت در درخواست خود عنوان می‌کند که به چه دسترسی‌هایی نیاز دارد. سوال: کلاینت از کجا متوجه می‌شود که اکسس توکن معتبری از کاربر ندارد؟ پاسخ: پروتکل OAuth در این مورد صحبتی نکرده است و تصمیم‌گیری بر عهده کلاینت است. معمولاً کلاینت‌ها اطلاعات Session کاربر را چک می‌کنند و در صورتی که اکسس توکن معتبر در Session کاربر وجود نداشته باشد، ریدایرکت به Authorization Server را انجام می‌دهند.مرحله سه: با دریافت 302، مرورگر یک درخواست GET به Location دریافتی ارسال می‌نماید.GET /auth?response_type=code&client_id=print-service&scope=read&redirect_uri=http://print-service.com/login/OAuth2/code/test HTTP/1.1 Host: auth-server.comمرحله چهار: به عنوان پاسخ، Authorization Server یک فرم لاگین به کاربر بر می‌گرداند. لازم به ذکر است که Authorization Server می‌تواند به روش دلخواه خود، کاربر یا مالک منبع را احراز هویت کند و از او اجازه بگیرد و پروتکل OAuth در این زمینه سکوت کرده است.HTTP/1.1 200 OK Content-Type: text/html <html> <body> <form>…</form> </body> </html>مرحله پنج: مالک منبع، نام کاربری و کلمه عبور را وارد کرده و بر روی دکمه ورود کلیک می‌کند. لذا درخواست زیر تولید شده و به Authorization Server ارسال می‌شود.POST /authenticate HTTP/1.1 Host: auth-server.com Content-Type: application/x-www-form-urlencoded username=user1&password=1234مرحله شش: Authorization Server نام کاربری و کلمه عبور را بررسی نموده و در صورت تایید مرورگر کاربر را به کلاینت ریدایرکت می‌کند.HTTP/1.1 302 Found Location: http://print-service.com/login/OAuth2/code/test?code=493...در پاسخ ملاحظه می‌کنید که کد به عنوان یک URL Parameter به مرورگر کاربر ارسال شده است. لازم به ذکر است که کد باید رشته‌ای باشد که غیر قابل حدس زدن باشد. در اینجا رشته به 493 خلاصه شده است.مرحله هفت: حال مرورگر کار با دریافت پاسخ ۳۰۱، یک در خواست get تولید نموده و به آدرس درج شده در هدر location ارسال می‌کند.GET /login/OAuth2/code/test?code=493... HTTP/1.1 Host: print-service.comهمانطور که ملاحظه نمودید، به این روش Authorization Code به کلاینت منتقل شد. در نتیجه کلاینت با استفاده از این کد می‌تواند از Authorization Server اکسس توکن را دریافت نماید.مرحله هشت: برای دریافت اکسس توکن با ارائه کد، درخواست زیر توسط کلاینت تولید شده و به Authorization Server و به Token Endpoint آن ارسال می‌شود.POST /token HTTP/1.1 Host: auth-server.com Content-Type: application/x-www-form-urlencoded grant_type=authorization_code&code=493…&redirect_uri=http://print-service.com/login/OAuth2/code/test&client_id=test&client_secret=passلازم به ذکر است که در این مرحله ضروری است کلاینت احراز هویت شود. لذا client_id و client_secret ای را که قبلاً از Authorization Server دریافت کرده است، در درخواست ارسال می‌کند. لازم به توضیح است که Authorization Code تنها برای کلاینت‌های از نوع Confidential قابل استفاده است.مرحله نه: در صورت معتبر بودن درخواست و نام کاربری و کلمه عبور کلاینت، Authorization Server در پاسخ اکسس توکن را به کلاینت ارائه می‌دهد.HTTP/1.1 200 OK Content-Type: application/json { “access_token”: “eyJ...”, “expires_in”: 300, “refresh_expires_in”: 1800, “refresh_token”: “eaZ...”, “token_type”: “Bearer”, “scope”: “profile email” }دو: Implicit GrantImplicit Grantاین گرنت مشابه Authorization Code هست و تنها یک مرحله از آن حذف شده است. در واقع به جای این که codeبه کلاینت ارسال شده و کلاینت با آن کد، اکسس توکن را دریافت کند، مستقیماً اکسس توکن به کلاینت داده خواهد شد.این نوع گرنت برای کلاینت هایی طراحی شده که به طور کامل در سمت دستگاه اجرا می‌شوند. مانندکلاینت های جاوا اسکریپتی مثل Angular، react، vue.js و ….لازم به ذکر است که استفاده از این نوع Grant به دلیل ضعف امنیتی نباید انجام شود. توصیه شده است به جای آن از Authorization Code همراه با PKCE استفاده شود. برای اطلاعات بیشتر در این خصوص به لینک https://OAuth.net/2/pkce مراجعه نمایید.سه: Resource owner password credentials grantResource Owner Password Credentials Grantدر این نوع Grant مالک منبع نام کاربری و کلمه عبور خود را در اختیار کلاینت قرار می‌دهد. زمانی که مالک منبع به کلاینت اعتماد کامل دارد این روش قابل استفاده است؛ به طور مثال در حالتی که Resource Serverو کلاینت هر دو توسط یک سازنده توسعه داده شده باشند.چهار: Client Credentials GrantClient Credentials Grantدر این نوع Grant، کلاینت همان مالک منبع است. لذا کلاینت با استفاده از Credentials خود (مانند client_id و client_secret) از Authorization Server اکسس توکن دریافت می‌کند.نکاتی در مورد OAuth2در بخش زیر نکاتی در خصوص پروتکل OAuth2 ذکر شده است.پروتکل OAuth، تنها با پروتکل HTTP قابل استفاده است.این پروتکل با OAuth 1 سازگار نیست. لذا اپلیکیشن‌های توسعه داده شده با OAuth 1 برای استفاده از OAuth 2 نیاز به بازنویسی دارند.مالک منبع می‌تواند به جای انسان، یک سیستم باشد. اگر مالک منبع یک انسان باشد به آن اصطلاحاً end-user نیز گفته می‌شود.پروتکل راجع به نحوه احراز هویت صحبتی نکرده است و تنها Authorization مد نظر بوده است. در توضیحات بالا نیز ذکر شد که Authorization Server تصمیم خواهد گرفت که به چه روشی کاربر یا مالک منبع را احراز هویت کند. از روش‌های احراز هویت متداول می‌تواند نام کاربری/کلمه عبور، رمزهای یکبار مصرف، ارسال کد تایید به تلفن همراه یا ایمیل کاربر، روش‌های بیومتریک نظیر اثر انگشت و … نام برد.نحوه ارتباط بین Resource Server و Authorization Server در پروتکل تعریف نشده است. عموماً برای اعتبارسنجی توکن در Resource Server از دو روش آفلاین و آنلاین استفاده می‌شود. در روش آفلاین، اکسس توکن (که عموماً به فرمت JWT است) امضای دیجیتال می‌شود و Resource Server با داشتن گواهی Authorization Server قادر به اعتبارسنجی آن خواهد بود. در روش آنلاین، توکن به Authorization Server ارسال شده و در پاسخ وضعیت اعتبار آن برگردانده می‌شود. به Endpoint ای در Authorization Server که این وظیفه را بر عهده دارد، Token Introspection Endpoint گفته می‌شود.امیدوارم مطلب براتون مفید بوده باشه. اگر جایی اشکالی میبینید، مبهم هست یا نکته ای وجود داره ممنون میشم در کامنت ها عنوان کنید. سپاس از این که وقت گذاشتید.