Security Fundamentals & Threat Modeling
CIA Triad, STRIDE, Attack Vectors, Defense in Depth
Introduction
Security engineering starts with a mindset: assume breach, design for failure, and layer your defenses. Before writing a single line of secure code, you need to understand what you are protecting, from whom, and how attackers think. This lesson establishes the foundational vocabulary and frameworks that every security engineer uses daily, the CIA Triad, threat modeling with STRIDE, attack vectors classification, and the defense-in-depth architecture principle.
The CIA Triad
The CIA Triad is the foundational framework for information security. Every security decision you make maps back to protecting one or more of these three properties.
Confidentiality
Data is accessible only to authorized parties.
- Encryption at rest
- Access control lists
- TLS in transit
- Least-privilege access
Integrity
Data has not been tampered with or altered.
- Cryptographic hashing
- Digital signatures
- Checksums (SHA-256)
- Version control & audit logs
Availability
Systems are accessible to authorized users when needed.
- Redundancy & failover
- DDoS protection
- Backup & disaster recovery
- Rate limiting
CIA in Practice
Security controls often involve trade-offs between CIA properties. A heavily encrypted, air-gapped system maximizes Confidentiality but may hurt Availability. Understanding your system's requirements helps you make informed trade-offs, not every system needs maximum protection for all three.
Threat Modeling with STRIDE
STRIDE is Microsoft's threat modeling framework. Each letter represents a threat category that maps to a CIA property. Use it to systematically identify threats during design, before you build.
| Letter | Threat Category | CIA Property Violated | Example Attack | Mitigation |
|---|---|---|---|---|
| S | Spoofing | Authentication | Fake identity, phishing | MFA, certificate pinning |
| T | Tampering | Integrity | MITM data modification | HMAC, digital signatures |
| R | Repudiation | Non-repudiation | Deny performing an action | Audit logs, signatures |
| I | Information Disclosure | Confidentiality | Data leak, SQL error messages | Encryption, input sanitization |
| D | Denial of Service | Availability | DDoS, resource exhaustion | Rate limiting, CDN, WAF |
| E | Elevation of Privilege | Authorization | Privilege escalation | Least privilege, RBAC |
Python: STRIDE Threat Report Generator
A practical Python script that models a system's components and generates a STRIDE threat assessment report.
# threat_model.py, STRIDE Threat Report Generator
from dataclasses import dataclass, field
from enum import Enum
from typing import List
class StrideCategory(Enum):
SPOOFING = "Spoofing"
TAMPERING = "Tampering"
REPUDIATION = "Repudiation"
INFO_DISCLOSURE = "Information Disclosure"
DENIAL_OF_SERVICE = "Denial of Service"
ELEVATION_OF_PRIVILEGE = "Elevation of Privilege"
class Severity(Enum):
LOW = "LOW"
MEDIUM = "MEDIUM"
HIGH = "HIGH"
CRITICAL = "CRITICAL"
@dataclass
class Threat:
category: StrideCategory
description: str
severity: Severity
component: str
mitigation: str
@dataclass
class SystemComponent:
name: str
component_type: str # e.g., "web_server", "database", "api_gateway"
threats: List[Threat] = field(default_factory=list)
def add_threat(self, threat: Threat) -> None:
self.threats.append(threat)
def threat_count_by_severity(self) -> dict:
counts = {s.value: 0 for s in Severity}
for t in self.threats:
counts[t.severity.value] += 1
return counts
def generate_stride_report(components: List[SystemComponent]) -> None:
total_threats = sum(len(c.threats) for c in components)
print("=" * 60)
print(" STRIDE THREAT MODEL REPORT")
print("=" * 60)
print(f"Components analyzed: {len(components)}")
print(f"Total threats identified: {total_threats}")
print()
for component in components:
print(f"[COMPONENT] {component.name} ({component.component_type})")
print(f" Threats: {len(component.threats)}")
counts = component.threat_count_by_severity()
for severity, count in counts.items():
if count > 0:
print(f" {severity}: {count}")
for threat in sorted(component.threats,
key=lambda t: list(Severity).index(t.severity),
reverse=True):
print(f" ┌─ [{threat.severity.value}] {threat.category.value}")
print(f" │ Description: {threat.description}")
print(f" └─ Mitigation: {threat.mitigation}")
print()
# ── Define your system ──────────────────────────────────────────
api_gateway = SystemComponent("API Gateway", "api_gateway")
api_gateway.add_threat(Threat(
category=StrideCategory.SPOOFING,
description="Attacker sends requests with forged JWT token",
severity=Severity.CRITICAL,
component="API Gateway",
mitigation="Validate JWT signature with RS256; use short expiry + refresh"
))
api_gateway.add_threat(Threat(
category=StrideCategory.DENIAL_OF_SERVICE,
description="Flood of unauthenticated requests exhausts connection pool",
severity=Severity.HIGH,
component="API Gateway",
mitigation="Implement rate limiting (100 req/min per IP) + WAF rules"
))
database = SystemComponent("PostgreSQL Database", "database")
database.add_threat(Threat(
category=StrideCategory.INFO_DISCLOSURE,
description="SQL error messages reveal table schema to attacker",
severity=Severity.MEDIUM,
component="PostgreSQL Database",
mitigation="Catch exceptions; return generic error messages to client"
))
database.add_threat(Threat(
category=StrideCategory.TAMPERING,
description="Unparameterized queries allow SQL injection data modification",
severity=Severity.CRITICAL,
component="PostgreSQL Database",
mitigation="Use parameterized queries / ORM; never interpolate user input"
))
generate_stride_report([api_gateway, database])Expected Output:
============================================================
STRIDE THREAT MODEL REPORT
============================================================
Components analyzed: 2
Total threats identified: 4
[COMPONENT] API Gateway (api_gateway)
Threats: 2
CRITICAL: 1
HIGH: 1
┌─ [CRITICAL] Spoofing
│ Description: Attacker sends requests with forged JWT token
└─ Mitigation: Validate JWT signature with RS256; use short expiry + refresh
┌─ [HIGH] Denial of Service
│ Description: Flood of unauthenticated requests exhausts connection pool
└─ Mitigation: Implement rate limiting (100 req/min per IP) + WAF rules
[COMPONENT] PostgreSQL Database (database)
Threats: 2
CRITICAL: 1
MEDIUM: 1
┌─ [CRITICAL] Tampering
│ Description: Unparameterized queries allow SQL injection data modification
└─ Mitigation: Use parameterized queries / ORM; never interpolate user input
┌─ [MEDIUM] Information Disclosure
│ Description: SQL error messages reveal table schema to attacker
└─ Mitigation: Catch exceptions; return generic error messages to clientAttack Vectors Overview
Understanding how attackers reach your system helps you prioritize your defensive investment.
Network Attacks
- Packet sniffing, Intercepting unencrypted traffic
- Port scanning, Discovering open services
- MITM, Intercepting and altering communications
- DNS poisoning, Redirecting traffic to malicious hosts
Social Engineering
- Phishing, Fraudulent emails/pages stealing credentials
- Spear phishing, Targeted phishing with personalization
- Pretexting, Fabricating scenarios to gain trust
- Vishing, Voice-based social engineering
Application Attacks
- SQL injection, Manipulating database queries
- XSS, Injecting malicious client-side scripts
- CSRF, Forging authenticated user actions
- Path traversal, Accessing unauthorized file paths
Supply Chain Attacks
- Dependency confusion, Malicious packages on public registries
- Typosquatting, Packages with similar names to popular ones
- Build system compromise, Injecting code in CI/CD pipeline
- Vendor compromise, Attacking via trusted third-party software
Defense in Depth
Defense in depth (DiD) means using multiple independent security layers. If one layer fails, additional layers continue to protect the system. No single control is a silver bullet.
# defense_in_depth.py, Model your security layers
from dataclasses import dataclass, field
from typing import List
@dataclass
class SecurityControl:
name: str
control_type: str # preventive, detective, corrective
effectiveness: str # low, medium, high
@dataclass
class SecurityLayer:
name: str
controls: List[SecurityControl] = field(default_factory=list)
def add_control(self, control: SecurityControl) -> None:
self.controls.append(control)
def coverage_score(self) -> float:
"""Returns % of high-effectiveness controls."""
if not self.controls:
return 0.0
high_count = sum(1 for c in self.controls if c.effectiveness == "high")
return (high_count / len(self.controls)) * 100
# Define defense layers
layers = [
SecurityLayer("Perimeter"),
SecurityLayer("Application"),
SecurityLayer("Data"),
]
layers[0].add_control(SecurityControl("WAF", "preventive", "high"))
layers[0].add_control(SecurityControl("Rate Limiter", "preventive", "high"))
layers[0].add_control(SecurityControl("IDS Alerts", "detective", "medium"))
layers[1].add_control(SecurityControl("Input Validation", "preventive", "high"))
layers[1].add_control(SecurityControl("SAST Scan", "detective", "medium"))
layers[2].add_control(SecurityControl("AES-256 Encryption", "preventive", "high"))
layers[2].add_control(SecurityControl("Access Logging", "detective", "high"))
print("Defense in Depth Analysis")
print("=" * 40)
for layer in layers:
score = layer.coverage_score()
status = "✅" if score >= 75 else "⚠️"
print(f"{status} {layer.name:15}, Coverage: {score:.0f}%")
for ctrl in layer.controls:
print(f" • {ctrl.name} ({ctrl.control_type}, {ctrl.effectiveness})")Expected Output:
Defense in Depth Analysis ======================================== ✅ Perimeter , Coverage: 67% • WAF (preventive, high) • Rate Limiter (preventive, high) • IDS Alerts (detective, medium) ⚠️ Application , Coverage: 50% • Input Validation (preventive, high) • SAST Scan (detective, medium) ✅ Data , Coverage: 100% • AES-256 Encryption (preventive, high) • Access Logging (detective, high)
Key Takeaways
- CIA Triad, Every security decision protects Confidentiality, Integrity, and/or Availability; understand the trade-offs
- STRIDE, Systematically enumerate threats during design: Spoofing, Tampering, Repudiation, Info Disclosure, DoS, Elevation of Privilege
- Attack vectors, Threats come from networks, social engineering, applications, and the software supply chain
- Defense in depth, Layer multiple independent controls; no single control is sufficient on its own
- Assume breach, Design systems expecting that any individual control will eventually fail
- Least privilege, Grant only the minimum permissions required; limit blast radius when breaches occur
What's Next?
Now that you understand the threat landscape and security principles, Lesson 2 dives into the mathematical tools that power modern security: cryptography.
- Hashing algorithms, SHA-256, SHA-3, and why MD5 is dead
- Symmetric encryption, Fernet and AES in Python
- Asymmetric encryption, RSA key pairs and digital signatures
- HMAC, Message authentication for integrity verification