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.