Спецификация: FAPI 2.0 Security Profile
FAPI 2.0 ужесточает OAuth 2.0 для API с высоким риском: только confidential-клиенты, pushed authorization requests, PKCE и токены с привязкой к отправителю. В Versola эти правила действуют для каждого клиента тенанта с профилем безопасности fapi2 — он выбирается по умолчанию для новых тенантов.
Versola пока не сертифицирована на FAPI 2.0, и сертификация соответствия не заявляется. Мы планируем её пройти. Versola не проходила набор тестов OpenID Foundation для FAPI 2.0, результаты conformance-набора не опубликованы. Каждый пункт ниже подтверждён кодом и сквозным тестом в репозитории продукта; названия тестов указаны в скобках.
Статус
Реализован частично. Отмечено пунктов: 31 из 35.
Регистрация клиента
central проверяет это при создании и изменении клиента и перечисляет все нарушения одной ошибкой.
- Только confidential-клиенты — публичный клиент (
authMethod: none) отклоняется при регистрации, а уже существующий публичный клиент получаетinvalid_clientна/token,/par,/introspectи/revoke(§5.3.2.1;SecurityProfileApiSpec,SecurityProfileRuntimeSpec) - Аутентификация клиента только через
private_key_jwt,tls_client_authилиself_signed_tls_client_auth— клиент сclient_secretотклоняется (§5.3.2.1;SecurityProfileApiSpec) - Access token с привязкой к отправителю обязательны — клиент ставит
dpopBoundAccessTokens, аутентифицируется сертификатом или ставитcertificateBoundAccessTokens(§5.3.2.2;SecurityProfileApiSpec) - Pushed authorization requests обязательны для каждого клиента с redirect URI —
requirePushedAuthorizationRequests(§5.3.2.2;SecurityProfileApiSpec) - Только
httpsredirect URI; loopbackhttpразрешён для native-клиентов и для любого клиента внеprod; private-use схемы отклоняются (§5.3.2.2;SecurityProfileApiSpec) - Изменение, которое вывело бы клиента из профиля, отклоняется (
SecurityProfileApiSpec) - Профиль фиксируется при создании тенанта и позже не переключается (
SecurityProfileApiSpec)
Authorization request
- Для обычного OAuth предлагается только authorization code flow — implicit и resource owner password grant не реализованы
- Pushed authorization requests —
POST /parвозвращает одноразовыйrequest_uri, привязанный к клиенту, который его отправил (см. RFC 9126;PushedAuthorizationSpec) - PKCE с
S256обязателен для каждого клиента, включая confidential;plainне принимается (см. RFC 7636;PushedAuthorizationSpec) - Redirect URI сравниваются по точному совпадению строки
- Ответ авторизации содержит
iss(см. RFC 9207) - Подписанные объекты запроса (JAR) принимаются:
nbfобязателен и не старше 60 минут,expне позже чем через 60 минут послеnbf,jtiобязателен и проверяется на replay,aud— ровно строка issuer (см. RFC 9101;JarFlowSpec) - Подписанные ответы авторизации JARM доступны как опция (см. JARM;
JarmFlowSpec) - Отказ для
response_type=code id_tokenу клиентовfapi2— не применяется; hybrid flow остаётся доступным на тенантеfapi2(с обязательнымnonce)
Аутентификация клиента
-
private_key_jwt:audдолжен быть ровно issuer, одной строкой; массив или URL endpoint отклоняются (§5.3.2.1-8;PrivateKeyJwtSpec) -
iatиnbfдо 60 с в будущем принимаются, дальше — отклоняются (§5.3.2.1-13;PrivateKeyJwtSpec) - Срок жизни assertion ограничен максимумом тенанта (30–900 с, по умолчанию 300 с), а каждый
jtiодноразовый (PrivateKeyJwtSpec) - Клиент с зарегистрированными ключами не может аутентифицироваться секретом, а два метода в одном запросе отклоняются (
PrivateKeyJwtSpec) -
tls_client_authиself_signed_tls_client_authна/token,/par,/introspectи/revoke— через listener mutual TLS или сертификат, пересланный прокси (см. RFC 8705;MutualTlsListenerSpec,MutualTlsSpec)
Token endpoint
- Authorization code одноразовые; повторное предъявление использованного code отзывает выданные по нему токены
-
Cache-Control: no-storeиPragma: no-cacheв ответах token endpoint - Refresh token привязаны к ключу или сертификату отправителя grant (см. RFC 9449 и RFC 8705;
MutualTlsSpec)
Токены с привязкой к отправителю
- DPoP proof проверяются по
typ, встроенномуjwk,htm,htu,iat,jtiиath, аcnf.jktпопадает в токен (см. RFC 9449) - Защита DPoP от replay общая для всех реплик
- Политика ключей DPoP: RSA-ключи короче 2048 бит отклоняются, а клиент может сузить допустимые алгоритмы (
DpopKeyPolicySpec) - Nonce от сервера для DPoP —
use_dpop_nonceиDPoP-Nonce, включается на тенанте черезrequireDpopNonce(по умолчанию выключено) - Токены с привязкой к сертификату:
cnf.x5t#S256в токене и в introspection, проверка на/userinfo(см. RFC 8705;MutualTlsSpec) - Токен, привязанный к ключу и предъявленный как
Bearer, отклоняется на/userinfoи наedge(DpopBoundTokenSpec)
Алгоритмы
- Тенант
fapi2не может выбрать ключ подписи RS256; ключи PS256 и ES256 принимаются (SigningKeySelectionSpec) - DPoP proof, client assertion и объекты запроса по умолчанию принимают
ES256иPS256;RS256в набор по умолчанию не входит - Исключение RS256 из списков алгоритмов DPoP, client assertion и объектов запроса для тенантов
fapi2— не применяется по тенантам; эти списки — метаданные на всё развёртывание, и оператор, добавивший тудаRS256, допускает его для всех тенантов -
EdDSA— не поддерживается
Resource server
-
edgeпроверяет DPoP proof,ath, привязку к ключу и replay на каждом проксируемом вызове и отклоняет токен, привязанный и к ключу, и к сертификату, при любом предъявлении (см. Edge;DpopBoundTokenSpec)
Транспорт
- Ограничения версии TLS и наборов шифров — Versola не применяет; TLS терминируется на обратном прокси или ingress, которые настраивает оператор
Примечания
- Профиль
standardне соответствует FAPI: он допускает client secret, публичных клиентов, ключи подписи RS256 и — для confidential-клиентов — запросы без PKCE. - Приложения за
edgeсохраняют форму FAPI на любом профиле: токены с привязкой к сертификату для web-клиентов, DPoP-токены и редиректы App Link для native. - Части FAPI 2.0 Message Signing (JAR, JARM) здесь — необязательные возможности, профиль их не навязывает.
Куда смотреть
Профили безопасности объясняют профили fapi2 и standard, а токены с привязкой к отправителю — привязку через DPoP и сертификат.