PKCE
PKCE (Proof Key for Code Exchange, RFC 7636, "pixy") — расширение OAuth 2.0, защищающее Authorization Code Flow от перехвата кода. Обязательный дефолт для public clients (mobile, SPA). В OAuth 2.1 — для всех.
Атака которую PKCE предотвращает
На mobile: приложение регистрирует custom-scheme:// для redirect_uri. Другое (вредоносное) приложение может зарегить тот же scheme и перехватить authorization code.
Раньше был client_secret — но в mobile его хранить негде.
Как работает
- Клиент генерит code_verifier — случайные 43-128 символов.
- Считает code_challenge = BASE64URL(SHA256(code_verifier)).
- В /authorize шлёт
code_challenge+code_challenge_method=S256. - AS запоминает.
- При обмене кода на токен — клиент шлёт
code_verifier. - AS считает SHA256, сверяет с ранее сохранённым challenge. Не совпало — отказ.
code_verifier = "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"
code_challenge = base64url(sha256(code_verifier))
= "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"
method: plain vs S256
- S256 — SHA256, обязательно рекомендуется
- plain — code_challenge == code_verifier. Тупо. Не использовать.
PKCE и confidential clients
Раньше считалось "с client_secret PKCE не нужен". Теперь (OAuth 2.1, BCP): нужен всем. Второй слой защиты.
Реализация
# JS
const verifier = crypto.getRandomValues(new Uint8Array(32));
const v_b64 = base64url(verifier);
const challenge = base64url(await crypto.subtle.digest('SHA-256', verifier));
localStorage.setItem('pkce_verifier', v_b64);
window.location = `${authURL}?...&code_challenge=${challenge}&code_challenge_method=S256`;