چه مشکلی را PKCE حل می‌کند؟

در یک برنامه مرورگری، کد JavaScript در اختیار کاربر است؛ بنابراین client secret که داخل آن نوشته شود واقعاً راز نیست. جریان Authorization Code با PKCE برای کلاینت‌هایی که نمی‌توانند راز ثابت نگه دارند، ارتباط میان شروع ورود و دریافت توکن را تقویت می‌کند. برنامه یک verifier تصادفی می‌سازد و مشتق آن، challenge، را با درخواست ورود می‌فرستد. هنگام تبادل کد، verifier ارائه می‌شود تا گرفتن کد به‌تنهایی برای دریافت توکن کافی نباشد. این کنترل مهم است، اما تمام مسئله امنیت ورود را حل نمی‌کند.

سه مفهوم را از هم جدا کنید. OAuth درباره دسترسی به منابع است؛ برای احراز هویت معمولاً OpenID Connect در کنار آن استفاده می‌شود. PKCE ارتباط کد و آغازکننده را بررسی می‌کند، state پاسخ را به تلاش مشخص ورود مرتبط می‌سازد و nonce در جریان OIDC برای بررسی ID token اهمیت دارد. نمونه زیر فقط ساخت verifier، challenge و state را نشان می‌دهد. این مثال کتابخانه ورود کامل نیست و نباید با اضافه کردن یک URL دلخواه به‌عنوان راهکار آماده بهره‌برداری معرفی شود.

ورود را یک جریان کامل ببینید

برای پیاده‌سازی واقعی، SDK نگهداری‌شده ارائه‌دهنده هویت را انتخاب کنید و redirect URI را دقیق ثبت کنید. مسیر بازگشت نباید هر نشانی ارسال‌شده از کاربر را بپذیرد. HTTPS، دامنه معتبر صادرکننده و تنظیمات مجاز کلاینت بخشی از قرارداد هستند. verifier باید برای همان تلاش ورود نگهداری و بعد از مصرف پاک شود. اگر چند تب هم‌زمان وارد می‌شوند، ذخیره یک مقدار مشترک ممکن است تلاش‌ها را روی هم بنویسد؛ طراحی وضعیت باید این حالت و لغو ورود را هم پوشش دهد.

پس از callback، پاسخ را از نظر خطا و state بررسی کنید؛ سپس تبادل کد و کنترل توکن را از مسیر SDK انجام دهید. در API، access token با صادرکننده، مخاطب و زمان اعتبار مورد انتظار بررسی می‌شود. ID token را به‌جای access token برای API مصرف نکنید. PKCE جلوی اجرای JavaScript مخرب در صفحه را نمی‌گیرد؛ بنابراین XSS، سیاست محتوای صفحه و نحوه ذخیره توکن‌ها همچنان مهم‌اند. نوشتن توکن یا verifier در لاگ، گزارش خطا یا ابزار تحلیل رفتار کاربر نیز مرز امنیت را تضعیف می‌کند.

پیشنهاد تحریریه یک ماتریس آزمون ساده است: ورود موفق، state اشتباه، callback تکراری، کد منقضی، قطع شبکه، خروج و ورود در دو تب. آزمون ناموفق باید برنامه را به وضعیت روشن برگرداند، نه اینکه کاربر را نیمه‌وارد باقی بگذارد. اجازه دسترسی به صفحه را از مجوز عملیات جدا بسنجید؛ دیدن صفحه مدیریت به معنی مجاز بودن تغییر نقش نیست. برای خطاهای ورود، شناسه رخداد و نوع شکست کافی است؛ داده محرمانه درخواست را برای راحتی عیب‌یابی ثبت نکنید.

نمونه کد و روش بررسی

این مثال آموزشی برای فهم مسیر پیاده‌سازی نوشته شده است. نسخه‌ها و پیش‌نیازهای ذکرشده را در محیط آزمایش بررسی کنید؛ نکات زیر مشخص می‌کنند برای استفاده عملی چه چیزهایی باید تکمیل شوند.

ساخت پارامترها در کنسول مرورگر؛ بدون شروع ورود
const toBase64Url = bytes =>
  btoa(String.fromCharCode(...bytes))
    .replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');

const verifier = toBase64Url(crypto.getRandomValues(new Uint8Array(32)));
const digest = await crypto.subtle.digest(
  'SHA-256', new TextEncoder().encode(verifier)
);
const challenge = toBase64Url(new Uint8Array(digest));
const state = toBase64Url(crypto.getRandomValues(new Uint8Array(16)));

// Inspect only public shape information, never the secret verifier.
console.log({ verifierLength: verifier.length,
  challengeLength: challenge.length, method: 'S256', stateLength: state.length });

verifier و challenge باید هر کدام ۴۳ کاراکتر داشته باشند. نمونه فقط شکل پارامترها را ثبت می‌کند؛ verifier را نمایش یا ذخیره عمومی نمی‌کند. برای ارسال authorize، مدیریت state، callback و تبادل کد از SDK استفاده کنید. این قطعه کد عمداً نشستی ایجاد نمی‌کند و هیچ توکنی دریافت نمی‌کند.

آزمون امنیتی پیش از اتصال کاربران

جریان ورود را با یک برنامه آزمایشی و حساب‌های دارای نقش متفاوت بررسی کنید. پس از تثبیت callback و خروج، سراغ زمان اعتبار نشست، تازه‌سازی توکن و احراز هویت چندمرحله‌ای بروید. هر کدام تصمیمی جداگانه درباره تجربه کاربر و ریسک دارد. سند تحویل باید دامنه صادرکننده، مسیرهای بازگشت، سطح دسترسی API و روش پاسخ به رخداد را مشخص کند. حاصل خوب این کار ورود قابل اتکا و قابل پشتیبانی است؛ وجود PKCE در آدرس درخواست به‌تنهایی نشان‌دهنده امنیت کامل سامانه نیست.

چک‌لیست اجرای عملی

  • نمونه را در HTTPS یا localhost و با مرورگر دارای Web Crypto اجرا کنید.
  • برای جریان کامل از SDK معتبر استفاده کنید؛ client secret را در مرورگر نگذارید.
  • state، nonce در OIDC، redirect URI و اعتبار توکن را مطابق SDK بررسی کنید.
  • تلاش تکراری، دو تب، لغو ورود و خروج را کنار مسیر موفق آزمایش کنید.

توضیح‌ها و پیشنهادهای اجرایی این مطلب، تحلیل تحریریه دانشنامه لیان هستند.منابع: Auth0 — Authorization Code with PKCE · RFC 7636 — PKCE · RFC 9700 — OAuth security best current practice

این مطلب بازنویسی تحلیلی دانشنامه لیان بر پایه منبع اصلی است.مشاهده منبع اصلی