### 🚨 CRITICAL Security Fixes - **🔒 Open Redirect Protection**: Добавлена строгая валидация redirect_uri против whitelist доменов - **🔒 Rate Limiting**: Защита OAuth endpoints от брутфорса (10 попыток за 5 минут на IP) - **🔒 Logout Endpoint**: Критически важный endpoint для безопасного отзыва httpOnly cookies - **🔒 Provider Validation**: Усиленная валидация OAuth провайдеров с логированием атак - **🚨 GlitchTip Alerts**: Автоматические алерты безопасности в GlitchTip при критических событиях ### 🛡️ Security Modules - **auth/oauth_security.py**: Модуль безопасности OAuth с валидацией и rate limiting + GlitchTip алерты - **auth/logout.py**: Безопасный logout с поддержкой JSON API и browser redirect - **tests/test_oauth_security.py**: Комплексные тесты безопасности (11 тестов) - **tests/test_oauth_glitchtip_alerts.py**: Тесты интеграции с GlitchTip (8 тестов) ### 🔧 OAuth Improvements - **Minimal Flow**: Упрощен до минимума - только httpOnly cookie, нет JWT в URL - **Simple Logic**: Нет error параметра = успех, максимальная простота - **DRY Refactoring**: Устранено дублирование кода в logout и валидации ### 🎯 OAuth Endpoints - **Старт**: `v3.dscrs.site/oauth/{provider}` - с rate limiting и валидацией - **Callback**: `v3.dscrs.site/oauth/{provider}/callback` - безопасный redirect_uri - **Logout**: `v3.dscrs.site/auth/logout` - отзыв httpOnly cookies - **Финализация**: `testing.discours.io/oauth?redirect_url=...` - минимальная схема ### 📊 Security Test Coverage - ✅ Open redirect attack prevention - ✅ Rate limiting protection - ✅ Provider validation - ✅ Safe fallback mechanisms - ✅ Cookie security (httpOnly + Secure + SameSite) - ✅ GlitchTip integration (8 тестов алертов) ### 📝 Documentation - Создан `docs/oauth-minimal-flow.md` - полное описание минимального flow - Обновлена документация OAuth в `docs/auth/oauth.md` - Добавлены security best practices
This commit is contained in:
@@ -46,23 +46,74 @@ await oauth.revoke_oauth_tokens(user_id, "google")
|
||||
|
||||
## 🔧 OAuth Flow
|
||||
|
||||
### 1. Инициация OAuth
|
||||
```python
|
||||
# Frontend
|
||||
### 1. Инициация OAuth (Фронтенд)
|
||||
```javascript
|
||||
// Простой вызов без параметров - backend получит redirect_uri из Referer header
|
||||
const oauth = (provider: string) => {
|
||||
const state = crypto.randomUUID()
|
||||
localStorage.setItem('oauth_state', state)
|
||||
|
||||
const oauthUrl = `${coreApiUrl}/auth/oauth/${provider}?state=${state}&redirect_uri=${encodeURIComponent(window.location.origin)}`
|
||||
window.location.href = oauthUrl
|
||||
window.location.href = `https://v3.dscrs.site/oauth/${provider}`
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Backend Endpoints
|
||||
|
||||
#### GET `/oauth/{provider}`
|
||||
#### GET `/oauth/{provider}` - Старт OAuth
|
||||
```python
|
||||
@router.get("/auth/oauth/{provider}")
|
||||
# v3.dscrs.site/oauth/github
|
||||
# 1. Сохраняет redirect_uri из Referer header в Redis state
|
||||
# 2. Редиректит на провайдера с PKCE challenge
|
||||
```
|
||||
|
||||
#### GET `/oauth/{provider}/callback` - Callback
|
||||
```python
|
||||
# GitHub → v3.dscrs.site/oauth/github/callback?code=xxx&state=yyy
|
||||
# 1. Обменивает code на access_token
|
||||
# 2. Получает профиль пользователя
|
||||
# 3. Создает/обновляет пользователя
|
||||
# 4. Создает JWT сессию
|
||||
# 5. Устанавливает httpOnly cookie (для GraphQL)
|
||||
# 6. Редиректит на https://testing.discours.io/oauth?redirect_url=... (JWT в httpOnly cookie)
|
||||
```
|
||||
|
||||
### 3. Фронтенд финализация
|
||||
```javascript
|
||||
// https://testing.discours.io/oauth роут
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
const error = urlParams.get('error')
|
||||
const redirectUrl = urlParams.get('redirect_url') || '/'
|
||||
|
||||
if (error) {
|
||||
// Обработка ошибок OAuth
|
||||
console.error('OAuth error:', error)
|
||||
alert('Authentication failed. Please try again.')
|
||||
window.location.href = '/'
|
||||
} else {
|
||||
// Нет ошибки = успех! JWT уже в httpOnly cookie
|
||||
// SessionProvider загружает сессию из cookie
|
||||
await sessionProvider.loadSession()
|
||||
|
||||
// Редиректим на исходную страницу
|
||||
window.location.href = redirectUrl
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Единая аутентификация через httpOnly cookie
|
||||
```javascript
|
||||
// GraphQL клиент использует httpOnly cookie
|
||||
const client = new ApolloClient({
|
||||
uri: 'https://v3.dscrs.site/graphql',
|
||||
credentials: 'include', // ✅ Отправляет httpOnly cookie
|
||||
})
|
||||
|
||||
// Все API вызовы также используют httpOnly cookie
|
||||
fetch('/api/endpoint', {
|
||||
credentials: 'include' // ✅ Отправляет httpOnly cookie
|
||||
})
|
||||
```
|
||||
|
||||
### 4. Настройки провайдеров (админки)
|
||||
- **GitHub**: `https://v3.dscrs.site/oauth/github/callback`
|
||||
- **Google**: `https://v3.dscrs.site/oauth/google/callback`
|
||||
- **Twitter**: `https://v3.dscrs.site/oauth/twitter/callback`
|
||||
async def oauth_redirect(
|
||||
provider: str,
|
||||
state: str,
|
||||
|
||||
Reference in New Issue
Block a user