Безопасность
OAuth/OIDC: собери и проверь защищённый логин
Читать про CVE в OAuth — не то же самое, что доказать, что в твоей реализации их нет. Собери небольшой, но полный OIDC-логин на реальном authorization server, sender-constrain-ни API и затем сам атакуй каждую обязательную проверку — только adversarial-тест, падающий на сломанном пути, доказывает, что проверка действительно есть.
Преврати модель полного набора юнита в работающую, проверенную систему: authorization code с PKCE, полная валидация id_token с обработкой ротации JWKS, ротация refresh token с обнаружением replay, вызовы API с привязкой DPoP и дашборд наблюдаемости — каждая защищена тестом, доказывающим, что проверка держит.
Собери защищённый OIDC-логин и sender-constrained защищённый API на реальном authorization server (Auth0, Okta, Keycloak или Authentik), затем проведи аудит безопасности, доказывающий каждую обязательную проверку adversarial-тестом, который незащищённый путь провалил бы.
- Adversarial-набор тестов, где каждый тест прогоняет один сломанный путь и отклоняется: повторённый authorization code (PKCE), несовпадающий state, подделанный или alg=none id_token, id_token с неверным aud, повторно использованный refresh token (срабатывает обнаружение replay) и вызов DPoP с отсутствующим или неверным proof.
- Продемонстрированный сценарий ротации ключа JWKS: ротируй ключ подписи IdP (или эмулируй новый kid) и покажи, что логин продолжает работать, потому что обновление при промахе кэша тянет новый ключ вместо 401.
- Проверка хранения токенов: access token доказуемо отсутствует в localStorage, а refresh token лежит в куке httpOnly, недоступной JS (или эквивалент платформы).
- Дашборд показывает, что refresh_replay_detected_total увеличивается ровно один раз при прогоне теста на повторное использование refresh token, а id_token_validation_failure_total растёт по причине на каждый отклонённый тест id_token.
- Одностраничный отчёт аудита, сопоставляющий каждую обязательную проверку юнита (PKCE, точный redirect, восемь проверок id_token, ротация refresh, sender-constraint, валидация аудитории) с тестом, который её доказывает.
- Добавь PAR (Pushed Authorization Requests), чтобы параметры authorize никогда не попадали в URL браузера, и покажи, что их нет в истории и заголовках referrer.
- Добавь token introspection на высокочувствительный write-эндпоинт с кэшем introspection 30 с и продемонстрируй, что токен, отозванный на IdP, отклоняется внутри окна кэша, пока локальная валидация JWT всё ещё обслуживает read-путь.
- Добавь RFC 8707 Resource Indicators, чтобы токен, выпущенный для API-A, отклонялся API-B, и включи регрессионный тест, что aud равный other-api отвергается.
- Прогони тот же логин на втором authorization server (например, замени Keycloak на Auth0) и задокументируй, какие проверки потребовали изменения конфигурации, а какие были переносимы.
Это цикл, который ты запускаешь на каждой реальной интеграции OAuth: собрать поток с PKCE, полностью валидировать id_token с закреплённым алгоритмом и обновлением JWKS при промахе кэша, ротировать refresh token с обнаружением replay, sender-constrain-ить API через DPoP, хранить токены по модели угроз клиента и подключить наблюдаемость, вскрывающую компрометацию. Затем проверить adversarial — проверка, которую ты не атаковал, это проверка, которую ты не доказал. Сделав это раз на маленькой системе, ты превращаешь дисциплину полного набора в мышечную память для production.