Лучшие практики создания приложений OAuth 2.0

Info

Рекомендации по безопасной разработке и настройке приложений OAuth 2.0 в GitVerse.

Безопасное хранение Client Secret

  • никогда не храните Client Secret в клиентском коде (JavaScript в браузере, мобильные приложения). Secret должен быть доступен только на сервере;
  • используйте переменные окружения для хранения секрета на сервере (.env, секреты CI/CD);
  • не коммитьте Client Secret в репозитории. Добавьте файлы с секретами в .gitignore;
  • регенерируйте Secret сразу, если обнаружили его утечку.

Danger

Если Client Secret скомпрометирован, злоумышник может выдавать токены от имени вашего приложения.

Всегда используйте PKCE

PKCE (Proof Key for Code Exchange, RFC 7636) защищает от перехвата authorization code при передаче от сервера авторизации к клиенту. Механизм привязывает запрос авторизации и обмен кода на токен к единому криптографическому идентификатору, что делает бесполезным перехваченный код без знания code_verifier.

Info

Полное описание и пошаговый алгоритм PKCE см. в разделе Что такое PKCE?.

  • PKCE обязателен в GitVerse для всех типов клиентов (Публичных и Конфиденциальных) на GitVerse;
  • всегда используйте метод S256 (SHA-256), а не plain;
  • code_verifier должен состоять из случайных символов A-Z, a-z, 0-9, -, ., _, ~ (длина 43–128 символов);
  • храните code_verifier в безопасном хранилище клиента до обмена кода на токен.
code_challenge_method=S256

Danger

Без PKCE злоумышленник, перехвативший код авторизации (например, через прокси или скомпрометированный Redirect URI), сможет обменять его на access token.

Запрашивайте минимально необходимые scope

  • уважайте решение пользователя: если scope отклонены, приложение должно корректно обработать ошибку access_denied;
  • проверяйте выданные scope на стороне сервера, чтобы не использовать права, которые не были подтверждены.
ПлохоХорошо
scope=allscope=read:user read:repository
scope=write:repository write:issuescope=read:repository (если достаточно чтения)

Защита от CSRF

CSRF (Cross-Site Request Forgery) — атака, при которой злоумышленник заставляет аутентифицированного пользователя выполнить нежелательное действие на доверенном сайте без его ведома. В контексте OAuth 2.0 атака может привести к тому, что пользователь непреднамеренно авторизует злонамеренное приложение или выполнит несанкционированный callback.

Параметр state защищает от CSRF: сервер генерирует уникальное значение, привязанное к сессии пользователя, и проверяет его при возврате из авторизации. Если state не совпадает — запрос отвергается.

Info

Подробнее о CSRF-атаках и защите через параметр state см. в разделе Что такое CSRF?.

Всегда используйте параметр state при запросе авторизации:

  1. Сгенерируйте криптографически случайную строку (минимум 32 байта).
  2. Передайте ее в GET /authorize?state=....
  3. При callback проверьте, что возвращенный state точно совпадает с оригиналом.

Warning

Без проверки state приложение уязвимо для CSRF-атак.

Обработка истечения токенов

Access token живет 1 час. Приложение должно:

  1. Отслеживать ответы 401 Unauthorized.
  2. При получении 401 использовать refresh_token для получения нового access_token.
  3. Повторить запрос с новым токеном.
  4. Если refresh_token истек (30 дней) — направить пользователя на повторную авторизацию.

Валидация Redirect URI

  • точно сравнивайте redirect_uri при авторизации с зарегистрированным URI;
  • разрешайте только https:// для продакшн и http://localhost:* для разработки;
  • не используйте wildcard-URI в продакшн-окружении.

Loopback URI для локальной разработки

Для локальной разработки используйте loopback-адрес. Согласно RFC 8252, рекомендуется предпочитать числовой IP-адрес 127.0.0.1 вместо имени хоста localhost:

ВариантСтатус
http://127.0.0.1:PORT/callbackРекомендуется (RFC 8252 §8.3)
http://localhost:PORT/callbackРазрешен, но 127.0.0.1 предпочтительнее

Оба варианта работают, однако 127.0.0.1 снижает риск атак через подмену DNS на уровне локальной машины.

Безопасная работа с токенами

  • не логируйте access_token и refresh_token;
  • не передавайте токены в URL (только в заголовке Authorization: Bearer);
  • не кэшируйте refresh_token — при ротации старый токен становится недействительным;
  • храните токены в защищенном хранилище (encrypted storage, secure cookie для браузерных приложений).

Мониторинг подключенных приложений

  • регулярно проверяйте список подключенных приложений в Настройки → Приложения OAuth 2.0 → Подключенные приложения;
  • отзывайте доступ к приложениям, которые больше не используете;
  • обращайте внимание на дату последнего использования.

Тестирование перед развертыванием

  1. Тестируйте на loopback-адресе — используйте http://127.0.0.1:PORT или http://localhost:PORT как Redirect URI.
  2. Проверяйте обработку ошибок — убедитесь, что приложение корректно обрабатывает все коды ошибок OAuth 2.0.
  3. Проверьте PKCE-flow — убедитесь, что code_verifier правильно вычисляется и передается.
  4. Тестируйте сценарий истечения токена — убедитесь, что refresh-flow работает корректно.