افزونه PKCE مخفف عبارت Proof Key for Code Exchange است که یک تکنیک برای کلاینتهای عمومی توصیف میکند تا تهدیدات روند قبلی یعنی Authorization Code را کاهش دهد و از آنها جلوگیری کند.
کلیت کار این تکنیک این است که ابتدا یک رمز ایجاد میکند و سپس هنگام تبادل Authorization Code برای یک Access Token، دوباره از آن رمز استفاده میکند. به این ترتیب اگر authorization code، رهگیری شود و حمله ای اتفاق بیافتد، از آن جا که درخواست Token به رمز ساخته شده اولیه وابسته میباشد، این حمله بیاثر خواهد بود.
کلاینت عمومی و یا هر کلاینتی که نمیتواند Client Secret را مخفی نگه دارد، اگر از روش Authorization Code استفاده کند، در معرض حمله رهگیری کد مجوز (authorization code interception attack) قرار میگیرد. در این حمله، مهاجم authorization code را که از Authorization Serverدریافت میشود را رهگیری میکند و با استفاده از آن برای دستیابی به Access Token اقدام کند.
شکل زیر روال این حمله را نشان میدهد :
درادامه مراحل این نوع مجوز را باهم طی میکنیم
1- ایجاد Code Verifier و Code Challenge
همانطور که در مرحله گذشته، قبل از Authorization Code، پارامتر Client Secret را برای درخواست گرفتن Access Token به کار می بردیم، در این روش نیز از مورد مشابه ای استفاده خواهیم کرد. وقتی کلاینت درخواست مجوز را شروع میکند، به جای این که بلافاصله مرورگر را راهاندازی کند، یا بهتر است بگوییم قبل از تغییر مسیر کاربر به Authorization Server، ابتدا دو پارامتر Code Verifier و Code Challenge را ایجاد میکند.
Code Verifier یک رشته به صورت تصادفی با استفاده از کاراکترهایA-Z ،a-z ، 0-9 و علائم نگارشی است که بین 43 تا 128 کاراکتر طول دارد. کلاینتCode Verifier ای که ایجاد کرده است را برای استفاده بعدی باید ذخیره کند.
وقتی که کلاینت Code Verifier را تولید کرد، از آن برای ایجاد Code Challenge استفاده میکند.برای دستگاههایی که میتوانند یک هش SHA256 را تولید کنند، Code Challenge یک رشته BASE64-URL-encoded شده است یعنی به صورت زیر:
base64url(sha256(code_verifier))
اما کلاینتهایی که توانایی تولید یک هش SHA256 را ندارند، میتوانند از همان Code Verifier به عنوان Code Challenge استفاده کنند.
2- ایجاد Authorization URL و redirect کردن کاربر به Authorization Server
این مرحله اولین درخواست کلاینت به Authorization Server میباشد که مشابه مرحله ی اول در روش Authorization Code میباشد که در آن کاربر را به Authorization Server به همراه پارامترهایی redirect میکنیم. پارامترهایی که در این درخواست وجود دارد شامل تمام پارامترهای روش قبل و همچنین دو پارامتر جدید که مختص PKCE میباشد:
· response_type : نشان میدهد میکند که کلاینت منتظر دریافت authorization code است.
· client_id : شناسه کلاینت که شما هنگام ثبت برنامه خود دریافت کردید.
· redirect_uri : آدرس URL ای را نشان میدهد که کاربر پس از اتمام مجوز، کاربر را به آن برگرداند.
· state : رشته تصادفی ایجاد شده توسط کلاینت، که بعدا نیاز به تایید آن است. در حقیقت کلاینت یک رشته تصادفی تولید میکند و آن را در درخواست قرار میدهد. پس از آنکه کاربر مجوز برنامه را صادر کرد، باید بررسی کند که همان مقدار را برگردانده است یا خیر. این کار برای جلوگیری از حملات CSRF استفاده میشود.
· code_challenge : کد challenge که در مرحله ی تخست توسط کلاینت تولید شد.
· code_challenge_method : مقدار این پارامتر 2 حالت دارد: ساده یا یک رشته SHA256. این مقدار به verifier بستگی دارد که Code Challenge را در مرحله ی نخست چگونه تولید کرده است. اگر این پارامتر حذف شود، سرور حالت ساده را در نظر میگیرد.
https://authorization-server.com/auth
response_type=code
&client_id=29352915982374239857
&redirect_uri=https%3A%2F%2Fexample-app.com%2Fcallback
&scope=create+delete
&state=xcoiv98y2kd22vusuye3kch
&code_challenge=EPfZUBYUfGmdkAO1DqSbShlptf4EYSs5MyMIZJKur_k
&code_challenge_method=S256
کاربر به Authorization Server منتقل میشود و باید نام کاربری و رمز عبور خود را وارد کند. Authorization Server باید بتواند پارامتر code_challenge را در درخواست شناسایی کند. سپس Authorization Server مقدار code_challange را با مقدار Authorization Code که تولید کرده است، مرتبط کند. نحوه ارتباط به این صورت خواهد بود که یا آنها را در پایگاه داده ذخیره کند یا اگر از Authorization Codes به صورت رمزگذاری شده استفاده میکند، میتواند در خود کد درج نماید. سرور، Authorization Code را به صورت عادی بر میگرداند.
3- Verify کردن پارامتر State
بعد از این که کاربر بهAuthorization Server منتقل شد و درخواست کلاینت مبنی بر لاگین و دسترسی را تایید کرد مجددا به کلاینت redirect میشود که 2 پارامتر زیر درURL را نیز با خود به همراه دارد. این موارد مشابه روش قبل میباشد:
https://example-app.com/callback
?code=g0ZGZmNjVmOWIjNTk2NTk4ZTYyZGI3
&state=xcoiv98y2kd22vusuye3kch
تفاوتی که وجود دارد این است که مقدار state در اینجا کاملا ضروری نیست زیرا پارامترهای PKCE محافظت CSRF را فراهم میکنند. در عمل، اگر مطمئن هستید که سرور OAuth از PKCE پشتیبانی میکند، میتوانید به جای استفاده از state برای محافظت در برابر حملهCSRF ، از پارامترهای Code Verifier و Code Challenge استفاده کنید.
در هر صورت اگر از state استفاده شده باشد، بررسی میشود که آیا مقدار state ذخیره شده توسط کلاینت با state موجود در redirect url، مطابقت دارد یا نه. اگر مطابقت داشته باشد، مرحله ی بعد طی میشود.
4- مبادله Athorization Code
اکنون آماده تبادل authorization code برای دریافت یک Access Token هستید. کلاینت با پارامترهای زیر یک درخواست POST ایجاد میکند. علاوه بر پارامترهای تعریف شده درAuthorization Code Request ، در این روش کلاینت پارامتر code_verifier را نیز ارسال میکند. یک درخواست Access Token کامل شامل پارامترهای زیر است:
· grant_type : نوع Grant در درخواست token را نشان میدهد.
· code : کلاینت authorization code به دست آمده در redirect_uri را ارسال خواهد کرد.
· redirect_uri : همان redirect URL که در درخواست مجوز اولیه استفاده شده است.
· client_id : شناسه کلاینت ثبت شده در برنامه.
· code_verifier : همان Code Verifier که کلاینت در مرحله ی اول ایجاد کرده است.
POST https://authorization-server.com/token
grant_type=authorization_code
&client_id=29352915982374239857
&client_secret=ZKVW9TAuxn4yAo_4KcEdnwMJ0EVTiaMET3__s5DySVO6pcUt
&redirect_uri=https%3A%2F%2Fexample-app.com%2Fcallback
&code=g0ZGZmNjVmOWIjNTk2NTk4ZTYyZGI3
&code_verifier=AGGyNqIw8Is2T66HrP_4s9CSfUUy2TjpnWk6F1v7BpK8Ru3G
همانطور که میبینید، شما باید code verifier را در درخواست توکن ارسال کنید. Authorization Server بررسی میکند که آیا verifier و challeneg که در درخواست مجوز مورد استفاده قرار گرفته است با هم مطابقت دارد یا خیر. این کار تضمین میکند که اگر یک مهاجم، authorization code را رهگیری کرد، قادر به استفاده از آن نباشد.
از آنجا که code_challenge و code_challenge_method در ابتدا با authorization code همراه بودند، Authorization Server از قبل میداند از کدام روش (ساده یاSHA256) برای تایید code_verifier استفاده کند.
اگر روش ساده باشد، Authorization Server فقط نیاز دارد تا بررسی کند که کد ارائه شده مطابق با رشته مورد انتظار code_challenge است یا خیر.
اگر روش SHA256 باشد، Authorization Server میبایست code_verifier دریافت شده را با همان روشی که در مرحله ی نخست گفته شد (یعنی محاسبه SHA256 hash و سپس base64-url-encoding)رمز کند و نتیجه ی آن را با پارامتر code_challenge که در مرحله ی اول دریافت کرده بود، مقایسه کند.
5- دریافت پاسخ
اگر مرحله ی قبل با موفقیت انجام شد، آنگاه Authorization Server میتواند، یک Access Token صادر کرده و آن را در پاسخ به کلاینت قرار دهد و اگر ناموفق بود، خطای invalid_grant پاسخ دهد.
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
"token_type":"bearer",
"expires_in":3600,
"refresh_token":"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
"scope":"create delete"
}
با طی کردن این مراحل، اکنون کلاینت دارای یک Access Token است و میتواند از آن برای ایجاد درخواستهای API از طرف کاربر استفاده کند.
توجه داشته باشید که استفاده از افزونه PKCE باعث نمیشود مقدار یا پارامتر جدیدی به پاسخ سرور به کلاینت اضافه شود و همانطور که در ابتدای این بخش ذکر شد، برای حفاظت در برابر تهدیدات Authorization Code میباشد و در کاهش آنها تأثیر دارد، بنابراین کلاینتها همیشه میتوانند از افزونه PKCE استفاده کنند حتی اگر یک Authorization Server از آن پشتیبانی نکند چون مقدار پارامتر اضافهای نخواهد داشت که باعث ایجاد مشکل شده و یا درخواست ها به درستی اجرا نشوند.