A02:2021 - Cryptographic Failures

A02:2021 - Cryptographic Failures

Cryptographic failures, previously known as sensitive data exposure, occur when applications fail to properly protect sensitive data through encryption. This includes weak encryption algorithms, improper key management, and transmission of sensitive data in clear text.

# Python - Cryptographic Failures and Solutions

import os
import hashlib
import secrets
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.backends import default_backend
import base64

# VULNERABLE: Weak password hashing
def hash_password_vulnerable(password):
    # MD5 is cryptographically broken
    return hashlib.md5(password.encode()).hexdigest()

# VULNERABLE: Hardcoded encryption key
class VulnerableEncryption:
    def __init__(self):
        # Never hardcode keys!
        self.key = "my-secret-key-123"
    
    def encrypt(self, data):
        # Using deprecated algorithm
        from Crypto.Cipher import DES
        cipher = DES.new(self.key.encode()[:8], DES.MODE_ECB)
        return cipher.encrypt(data.ljust(8))

# SECURE: Proper password hashing with bcrypt
import bcrypt

def hash_password_secure(password):
    # Generate salt with cost factor 12
    salt = bcrypt.gensalt(rounds=12)
    
    # Hash password with salt
    hashed = bcrypt.hashpw(password.encode('utf-8'), salt)
    
    return hashed.decode('utf-8')

def verify_password_secure(password, hashed):
    return bcrypt.checkpw(password.encode('utf-8'), hashed.encode('utf-8'))

# SECURE: Proper encryption with key derivation
class SecureEncryption:
    def __init__(self, password: str):
        # Derive key from password using PBKDF2
        kdf = PBKDF2HMAC(
            algorithm=hashes.SHA256(),
            length=32,
            salt=self._get_or_create_salt(),
            iterations=100000,
            backend=default_backend()
        )
        key = base64.urlsafe_b64encode(kdf.derive(password.encode()))
        self.cipher = Fernet(key)
    
    def _get_or_create_salt(self):
        # Store salt separately from encrypted data
        salt_file = 'encryption.salt'
        
        if os.path.exists(salt_file):
            with open(salt_file, 'rb') as f:
                return f.read()
        else:
            salt = secrets.token_bytes(16)
            with open(salt_file, 'wb') as f:
                f.write(salt)
            return salt
    
    def encrypt(self, data: str) -> bytes:
        """Encrypt data using Fernet (AES-128 in CBC mode)"""
        return self.cipher.encrypt(data.encode())
    
    def decrypt(self, encrypted_data: bytes) -> str:
        """Decrypt data"""
        return self.cipher.decrypt(encrypted_data).decode()

# SECURE: Protecting data in transit
import ssl
import certifi

def create_secure_connection():
    # Create SSL context with strong settings
    context = ssl.create_default_context(cafile=certifi.where())
    
    # Disable weak protocols
    context.minimum_version = ssl.TLSVersion.TLSv1_2
    
    # Set strong cipher suites
    context.set_ciphers('ECDHE+AESGCM:ECDHE+CHACHA20:DHE+AESGCM:DHE+CHACHA20:!aNULL:!MD5:!DSS')
    
    return context

# SECURE: Secure data storage example
class SecureDataStorage:
    def __init__(self, master_password):
        self.encryption = SecureEncryption(master_password)
    
    def store_sensitive_data(self, data_type, data):
        # Validate data type
        allowed_types = ['credit_card', 'ssn', 'api_key']
        if data_type not in allowed_types:
            raise ValueError(f"Unknown data type: {data_type}")
        
        # Encrypt before storage
        encrypted = self.encryption.encrypt(data)
        
        # Store with metadata
        storage_record = {
            'type': data_type,
            'encrypted_data': base64.b64encode(encrypted).decode(),
            'timestamp': datetime.utcnow().isoformat(),
            'version': '1.0'
        }
        
        # Save to secure storage (database, file, etc.)
        return self._save_to_storage(storage_record)
// JavaScript - Cryptographic Failures and Solutions

const crypto = require('crypto');
const bcrypt = require('bcrypt');

// VULNERABLE: Weak hashing
function hashPasswordVulnerable(password) {
    // SHA-1 is deprecated for passwords
    return crypto.createHash('sha1').update(password).digest('hex');
}

// VULNERABLE: Insecure random token generation
function generateTokenVulnerable() {
    // Math.random() is not cryptographically secure
    return Math.random().toString(36).substring(2);
}

// VULNERABLE: Hardcoded secrets
const vulnerableConfig = {
    jwtSecret: 'my-secret-key',  // Never hardcode!
    encryptionKey: '1234567890123456'
};

// SECURE: Proper password hashing with bcrypt
async function hashPasswordSecure(password) {
    const saltRounds = 12;
    return await bcrypt.hash(password, saltRounds);
}

async function verifyPasswordSecure(password, hash) {
    return await bcrypt.compare(password, hash);
}

// SECURE: Cryptographically secure random tokens
function generateSecureToken(length = 32) {
    return crypto.randomBytes(length).toString('hex');
}

// SECURE: Proper encryption class
class SecureEncryption {
    constructor() {
        // Generate or load key from secure storage
        this.algorithm = 'aes-256-gcm';
        this.key = this.getOrCreateKey();
    }
    
    getOrCreateKey() {
        // In production, use a key management service
        const keyFile = '.encryption.key';
        
        try {
            // Try to load existing key
            const key = fs.readFileSync(keyFile);
            return key;
        } catch (error) {
            // Generate new key
            const key = crypto.randomBytes(32);
            fs.writeFileSync(keyFile, key, { mode: 0o600 });
            return key;
        }
    }
    
    encrypt(text) {
        const iv = crypto.randomBytes(16);
        const cipher = crypto.createCipheriv(this.algorithm, this.key, iv);
        
        let encrypted = cipher.update(text, 'utf8', 'hex');
        encrypted += cipher.final('hex');
        
        const authTag = cipher.getAuthTag();
        
        return {
            encrypted,
            iv: iv.toString('hex'),
            authTag: authTag.toString('hex')
        };
    }
    
    decrypt(encryptedData) {
        const decipher = crypto.createDecipheriv(
            this.algorithm,
            this.key,
            Buffer.from(encryptedData.iv, 'hex')
        );
        
        decipher.setAuthTag(Buffer.from(encryptedData.authTag, 'hex'));
        
        let decrypted = decipher.update(encryptedData.encrypted, 'hex', 'utf8');
        decrypted += decipher.final('utf8');
        
        return decrypted;
    }
}

// SECURE: Environment-based configuration
class SecureConfig {
    constructor() {
        this.config = {
            jwtSecret: process.env.JWT_SECRET || this.generateAndStoreSecret('JWT_SECRET'),
            encryptionKey: process.env.ENCRYPTION_KEY || this.generateAndStoreSecret('ENCRYPTION_KEY'),
            dbEncryptionKey: process.env.DB_ENCRYPTION_KEY || this.generateAndStoreSecret('DB_ENCRYPTION_KEY')
        };
        
        // Validate all secrets are present
        this.validateSecrets();
    }
    
    generateAndStoreSecret(name) {
        const secret = crypto.randomBytes(32).toString('hex');
        
        // In development, write to .env file
        if (process.env.NODE_ENV === 'development') {
            fs.appendFileSync('.env', `\n${name}=${secret}\n`);
            console.warn(`Generated new ${name}. Please restart the application.`);
        } else {
            throw new Error(`${name} not found in environment variables`);
        }
        
        return secret;
    }
    
    validateSecrets() {
        Object.entries(this.config).forEach(([key, value]) => {
            if (!value || value.length < 32) {
                throw new Error(`Invalid secret for ${key}`);
            }
        });
    }
}

// SECURE: HTTPS enforcement in Express
const enforceHTTPS = (req, res, next) => {
    if (req.header('x-forwarded-proto') !== 'https') {
        return res.redirect(`https://${req.header('host')}${req.url}`);
    }
    next();
};

app.use(enforceHTTPS);

// Set security headers
app.use((req, res, next) => {
    res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
    res.setHeader('X-Content-Type-Options', 'nosniff');
    res.setHeader('X-Frame-Options', 'DENY');
    res.setHeader('X-XSS-Protection', '1; mode=block');
    next();
});

Understanding how the OWASP Top 10 vulnerabilities manifest in Python and JavaScript is crucial for writing secure code. Each vulnerability requires specific mitigation strategies adapted to the language and framework being used. By implementing these secure coding practices, developers can significantly reduce the risk of security breaches in their applications.## Authentication and Authorization Patterns

Authentication and authorization are fundamental pillars of application security, determining who can access your system and what they can do once inside. Python and JavaScript applications face unique challenges in implementing these security controls, particularly in distributed architectures where authentication state must be managed across multiple services. This chapter explores secure patterns for implementing authentication and authorization in both languages, covering everything from password handling to token-based authentication and role-based access control.