Lab 02: Threat Modeling with STRIDE¶
| Field | Details |
|---|---|
| Course | SCIA-425 โ Software Assurance and Quality |
| Week | 3 |
| Difficulty | โญโญ Intermediate |
| Estimated Time | 90 minutes |
| Topic | Threat Modeling โ Systematic Security Analysis |
| Prerequisites | Python 3.10+, pip install pytm |
| Deliverables | threat_model.py, generated DFD, stride_analysis.json, threat_report.md |
Overview¶
Threat modeling is the systematic process of identifying and prioritizing threats before code is written. In this lab you will model a Telehealth Appointment System using the STRIDE methodology, generate a Data Flow Diagram (DFD) programmatically using the pytm library, enumerate threats for each element, and produce a structured threat report with mitigations.
STRIDE categories: | Letter | Threat | Violated Property | |--------|--------|-------------------| | S | Spoofing | Authentication | | T | Tampering | Integrity | | R | Repudiation | Non-repudiation | | I | Information Disclosure | Confidentiality | | D | Denial of Service | Availability | | E | Elevation of Privilege | Authorization |
Docker Required for pytm DFD generation
pytm requires Graphviz. Use the provided Docker command instead of installing locally.
System Description¶
The Telehealth Appointment System has these components:
- Patient Browser โ Web client used by patients
- Web Application Server โ Handles appointment booking and video session setup
- Authentication Service โ Issues JWT tokens, validates credentials
- Database โ Stores patient records, appointments, provider schedules
- Video Service โ Third-party integration (e.g., Zoom API)
- Audit Log Service โ Writes immutable event logs to separate storage
Data flows: 1. Patient โ Web App: Login credentials (HTTPS) 2. Web App โ Auth Service: Token request (internal, TLS) 3. Auth Service โ Web App: JWT token (internal, TLS) 4. Web App โ Database: Patient queries (internal, encrypted) 5. Web App โ Video Service: Session creation (HTTPS, API key) 6. Web App โ Audit Log: Event write (internal, append-only)
Part A โ Build the DFD with pytm (25 pts)¶
Create threat_model.py that generates a DFD for the system above:
from pytm import TM, Actor, Process, Datastore, Dataflow, Boundary, Classification
tm = TM("Telehealth Appointment System")
tm.description = "SCIA-425 Lab 02 โ STRIDE threat model"
tm.isOrdered = True
# Boundaries
internet = Boundary("Internet")
internal = Boundary("Internal Network")
data_tier = Boundary("Data Tier")
# Elements
patient = Actor("Patient Browser")
patient.inBoundary = internet
web_app = Process("Web Application Server")
web_app.inBoundary = internal
auth_svc = Process("Authentication Service")
auth_svc.inBoundary = internal
database = Datastore("Patient Database")
database.inBoundary = data_tier
database.isEncrypted = True
video_svc = Actor("Video Service (3rd Party)")
video_svc.inBoundary = internet
audit_log = Datastore("Audit Log Service")
audit_log.inBoundary = data_tier
# Dataflows โ complete all 6
df1 = Dataflow(patient, web_app, "Login Credentials")
df1.protocol = "HTTPS"
df1.isEncrypted = True
df1.data = Classification.PII
df2 = Dataflow(web_app, auth_svc, "Token Request")
df2.protocol = "TLS"
df2.isEncrypted = True
df3 = Dataflow(auth_svc, web_app, "JWT Token")
df3.protocol = "TLS"
df3.isEncrypted = True
df4 = Dataflow(web_app, database, "Patient Query")
df4.protocol = "TLS"
df4.isEncrypted = True
df4.data = Classification.PII
df5 = Dataflow(web_app, video_svc, "Session Creation")
df5.protocol = "HTTPS"
df5.isEncrypted = True
df6 = Dataflow(web_app, audit_log, "Event Write")
df6.protocol = "TLS"
df6.isEncrypted = True
tm.process()
Run it and save the generated DFD image as dfd.png. Include it in your report.
Expected output: A DFD showing all 6 elements and 6 dataflows across 3 trust boundaries.
Part B โ STRIDE Analysis (40 pts)¶
For each of the 6 system elements, apply all 6 STRIDE categories. Record your findings in stride_analysis.json:
[
{
"element": "Web Application Server",
"element_type": "Process",
"threats": [
{
"stride_category": "Spoofing",
"applies": true,
"description": "Attacker sends requests impersonating a legitimate patient session using a stolen JWT",
"likelihood": "Medium",
"impact": "High",
"risk_score": 6,
"mitigation": "Implement JWT binding to client IP and user-agent; short token expiry (15 min)"
},
{
"stride_category": "Tampering",
"applies": true,
"description": "Attacker modifies appointment data in transit by intercepting an unencrypted internal connection",
"likelihood": "Low",
"impact": "High",
"risk_score": 4,
"mitigation": "Enforce TLS on all internal dataflows; validate HMAC signatures on appointment records"
}
]
}
]
Requirements: - Cover all 6 elements - For each element, evaluate all 6 STRIDE categories (mark "applies": false with brief justification if not applicable) - risk_score = likelihood ร impact on 1-3 scale (1=Low, 2=Med, 3=High), so range 1โ9 - At least 15 total applicable threats across all elements
Part C โ Attack Tree (15 pts)¶
Choose the highest risk_score threat from your STRIDE analysis. Draw an attack tree for it in ASCII or Markdown:
GOAL: Attacker reads patient ePHI without authorization
โโโ OR
โ โโโ Steal valid JWT token
โ โ โโโ AND
โ โ โ โโโ Compromise patient device (malware)
โ โ โ โโโ Extract token from browser storage
โ โ โโโ Intercept token in transit
โ โ โโโ Downgrade TLS connection (requires network position)
โ โโโ Exploit SQL injection in patient query endpoint
โ โ โโโ Find injectable parameter (automated scanner)
โ โ โโโ Extract rows from patient table
โ โโโ Compromise Auth Service
โ โโโ Steal signing key
โ โโโ Forge arbitrary JWT
Include this tree in threat_report.md. Annotate each leaf node with: [FEASIBLE/MITIGATED/RESIDUAL RISK].
Part D โ Threat Report (20 pts)¶
Write threat_report.md with these sections:
- System Overview โ 1 paragraph, include the DFD image
- Threat Summary Table โ aggregate by STRIDE category: count of applicable threats, avg risk score, top finding
- Top 3 Risks โ full description, risk score, recommended mitigation priority
- Attack Tree โ from Part C
- Residual Risk Statement โ what threats remain after mitigations, and why they are accepted
Verification Script¶
Run this to check your stride_analysis.json is complete:
# verify_lab02.py
import json, sys
with open("stride_analysis.json") as f:
data = json.load(f)
STRIDE = ["Spoofing","Tampering","Repudiation","Information Disclosure","Denial of Service","Elevation of Privilege"]
ELEMENTS = ["Web Application Server","Authentication Service","Patient Database","Patient Browser","Video Service (3rd Party)","Audit Log Service"]
print(f"Elements analyzed: {len(data)}")
for elem in data:
cats = {t["stride_category"] for t in elem["threats"]}
missing = set(STRIDE) - cats
if missing:
print(f" WARN {elem['element']}: missing {missing}")
applicable = [t for e in data for t in e["threats"] if t.get("applies")]
print(f"Total applicable threats: {len(applicable)}")
if len(applicable) < 15:
print("FAIL: Need at least 15 applicable threats"); sys.exit(1)
high_risk = [t for t in applicable if t.get("risk_score", 0) >= 6]
print(f"High-risk threats (score โฅ6): {len(high_risk)}")
print("PASS: stride_analysis.json verified.")
Submission Checklist¶
- [ ]
threat_model.pyโ pytm model (runs without error) - [ ]
dfd.pngโ generated Data Flow Diagram - [ ]
stride_analysis.jsonโ verified (15+ applicable threats) - [ ]
threat_report.mdโ all 5 sections present - [ ]
verify_lab02.pyoutput showing PASS
Grading¶
| Component | Points |
|---|---|
| Part A โ DFD generated (6 elements, 6 flows, 3 boundaries) | 25 |
| Part B โ STRIDE analysis (15+ threats, all elements covered) | 40 |
| Part C โ Attack tree (correct structure, annotated leaves) | 15 |
| Part D โ Threat report (all 5 sections, professional quality) | 20 |
| Total | 100 |