diff --git a/labs/lab2/threagile-model-auth.yaml b/labs/lab2/threagile-model-auth.yaml new file mode 100644 index 000000000..8ee451d7a --- /dev/null +++ b/labs/lab2/threagile-model-auth.yaml @@ -0,0 +1,329 @@ +threagile_version: 1.0.0 + +title: Juice Shop Auth Flow +date: 2026-06-12 +author: + name: Student +business_criticality: critical + +business_overview: + description: Targeted threat model focusing strictly on the JWT-based authentication and authorization flow. + +technical_overview: + description: The user browser submits credentials to the Auth API. The Auth API checks the User DB and requests a token from the Token Manager. The user then uses this JWT to access the Admin API, which verifies the token signature. +tags_available: + - auth + - pii + - tokens + - state + - admin + - actor + - client + - login + - admin-ui + - api + - db-query + - internal + - crypto + - db +# ========================= +# DATA ASSETS +# ========================= +data_assets: + Credentials: + id: credentials + description: "Usernames and passwords for login." + usage: business + tags: ["auth", "pii"] + origin: user-supplied + owner: Lab Owner + quantity: many + confidentiality: confidential + integrity: critical + availability: important + justification_cia_rating: "Compromise leads to full account takeover." + + JWT Token: + id: jwt-token + description: "JSON Web Token containing user identity and roles." + usage: business + tags: ["auth", "tokens"] + origin: application + owner: Lab Owner + quantity: many + confidentiality: confidential + integrity: critical + availability: important + justification_cia_rating: "Used for session state and authorization." + + Session State: + id: session-state + description: "Client-side state tracking the active login." + usage: business + tags: ["state"] + origin: application + owner: Lab Owner + quantity: many + confidentiality: confidential + integrity: important + availability: important + justification_cia_rating: "Client-side representation of session." + + Admin Requests: + id: admin-requests + description: "Requests invoking privileged administrative functions." + usage: business + tags: ["admin"] + origin: application + owner: Lab Owner + quantity: few + confidentiality: internal + integrity: critical + availability: important + justification_cia_rating: "Must be protected from unauthorized users." + +# ========================= +# TECHNICAL ASSETS +# ========================= +technical_assets: + User Browser: + id: user-browser + description: "End-user web browser." + type: external-entity + usage: business + used_as_client_by_human: true + out_of_scope: false + size: system + technology: browser + tags: ["actor", "client"] + internet: true + machine: virtual + encryption: none + owner: External User + confidentiality: public + integrity: operational + availability: operational + justification_cia_rating: "Untrusted client." + multi_tenant: false + redundant: false + custom_developed_parts: false + data_assets_processed: + - session-state + data_assets_stored: + - jwt-token + data_formats_accepted: + - json + communication_links: + Login Link: + target: auth-api + description: "Browser sends credentials to login endpoint." + protocol: https + authentication: none + authorization: none + tags: ["login"] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - credentials + data_assets_received: + - jwt-token + Admin Access Link: + target: admin-api + description: "Browser accesses privileged endpoints using JWT." + protocol: https + authentication: credentials + authorization: enduser-identity-propagation + tags: ["admin-ui"] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - admin-requests + - jwt-token + data_assets_received: [] + + Auth API: + id: auth-api + description: "Endpoint handling login and registration." + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + size: component + technology: web-server + tags: ["api", "login"] + internet: false + machine: container + encryption: none + owner: Lab Owner + confidentiality: internal + integrity: critical + availability: important + justification_cia_rating: "Gatekeeper for authentication." + multi_tenant: false + redundant: false + custom_developed_parts: true + data_assets_processed: + - credentials + - jwt-token + data_assets_stored: [] + data_formats_accepted: + - json + communication_links: + DB Lookup: + target: user-db + description: "Verify credentials against stored hashes." + protocol: jdbc + authentication: credentials + authorization: none + tags: ["db-query"] + vpn: false + ip_filtered: false + readonly: true + usage: business + data_assets_sent: + - credentials + data_assets_received: + - credentials + Token Request: + target: token-manager + description: "Request a signed JWT for valid login." + protocol: in-process-library-call + authentication: none + authorization: none + tags: ["internal"] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - credentials + data_assets_received: + - jwt-token + + Token Manager: + id: token-manager + description: "Component handling JWT signing and verification." + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + size: component + technology: web-server + tags: ["crypto"] + internet: false + machine: container + encryption: none + owner: Lab Owner + confidentiality: confidential + integrity: critical + availability: important + justification_cia_rating: "Holds signing keys; critical for integrity." + multi_tenant: false + redundant: false + custom_developed_parts: true + data_assets_processed: + - jwt-token + data_assets_stored: [] + data_formats_accepted: + - json + communication_links: {} + + Admin API: + id: admin-api + description: "Privileged endpoints requiring Admin role in JWT." + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + size: component + technology: web-server + tags: ["api", "admin"] + internet: false + machine: container + encryption: none + owner: Lab Owner + confidentiality: internal + integrity: critical + availability: important + justification_cia_rating: "Processes high-risk administrative operations." + multi_tenant: false + redundant: false + custom_developed_parts: true + data_assets_processed: + - admin-requests + - jwt-token + data_assets_stored: [] + data_formats_accepted: + - json + communication_links: + Verify Token: + target: token-manager + description: "Check JWT signature and roles." + protocol: in-process-library-call + authentication: none + authorization: none + tags: ["internal"] + vpn: false + ip_filtered: false + readonly: true + usage: business + data_assets_sent: + - jwt-token + data_assets_received: [] + + User DB: + id: user-db + description: "Database storing user credentials." + type: datastore + usage: business + used_as_client_by_human: false + out_of_scope: false + size: component + technology: database + tags: ["db"] + internet: false + machine: container + encryption: data-with-symmetric-shared-key + owner: Lab Owner + confidentiality: confidential + integrity: critical + availability: important + justification_cia_rating: "Source of truth for auth." + multi_tenant: false + redundant: false + custom_developed_parts: false + data_assets_processed: [] + data_assets_stored: + - credentials + data_formats_accepted: + - json + communication_links: {} + +# ========================= +# TRUST BOUNDARIES +# ========================= +trust_boundaries: + Internet: + id: internet + description: "Untrusted network." + type: network-dedicated-hoster + tags: [] + technical_assets_inside: + - user-browser + trust_boundaries_nested: [] + + Container Network: + id: container-network + description: "Isolated Docker network." + type: network-dedicated-hoster + tags: [] + technical_assets_inside: + - auth-api + - admin-api + - token-manager + - user-db + trust_boundaries_nested: [] diff --git a/labs/lab2/threagile-model-secure.yaml b/labs/lab2/threagile-model-secure.yaml new file mode 100644 index 000000000..7506d7827 --- /dev/null +++ b/labs/lab2/threagile-model-secure.yaml @@ -0,0 +1,429 @@ +threagile_version: 1.0.0 + +title: Juice Shop Model +date: 2025-09-18 + +author: + name: Student Name + homepage: https://example.edu + +management_summary_comment: > + Threat model for a local OWASP Juice Shop setup. Users access the app + either directly via HTTP on port 3000 or through an optional reverse proxy that + terminates TLS and adds security headers. The app runs in a container + and writes data to a host-mounted volume (for database, uploads, logs). + Optional outbound notifications (e.g., a challenge-solution WebHook) can be configured for integrations. + +business_criticality: important # archive, operational, important, critical, mission-critical + +business_overview: + description: > + Training environment for DevSecOps. This model covers a deliberately vulnerable + web application (OWASP Juice Shop) running locally in a Docker container. The focus is on a minimal architecture, STRIDE threat analysis, and actionable mitigations for the identified risks. + + images: + # - dfd.png: Data Flow Diagram (if exported from the tool) + +technical_overview: + description: > + A user’s web browser connects to the Juice Shop application (Node.js/Express server) either directly on **localhost:3000** (HTTP) or via a **reverse proxy** on ports 80/443 (with HTTPS). The Juice Shop server may issue outbound requests to external services (e.g., a configured **WebHook** for solved challenge notifications). All application data (the SQLite database, file uploads, logs) is stored on the host’s filesystem via a mounted volume. Key trust boundaries include the **Internet** (user & external services) → **Host** (local machine/VM) → **Container Network** (isolated app container). + images: [] + +questions: + Do you expose port 3000 beyond localhost?: "" + Do you use a reverse proxy with TLS and security headers?: "" + Are any outbound integrations (webhooks) configured?: "" + Is any sensitive data stored in logs or files?: "" + +abuse_cases: + Credential Stuffing / Brute Force: > + Attackers attempt repeated login attempts to guess credentials or exhaust system resources. + Stored XSS via Product Reviews: > + Malicious scripts are inserted into product reviews, getting stored and executed in other users’ browsers. + SSRF via Outbound Requests: > + Server-side requests (e.g. profile image URL fetch or WebHook callback) are abused to access internal network resources. + +security_requirements: + TLS in transit: Enforce HTTPS for user traffic via a TLS-terminating reverse proxy with strong ciphers and certificate management. + AuthZ on sensitive routes: Implement strict server-side authorization checks (role/permission) on admin or sensitive functionalities. + Rate limiting & lockouts: Apply rate limiting and account lockout policies to mitigate brute-force and automated attacks on authentication and expensive operations. + Secure headers: Add security headers (HSTS, CSP, X-Frame-Options, X-Content-Type-Options, etc.) at the proxy or app to mitigate client-side attacks. + Secrets management: Protect secret keys and credentials (JWT signing keys, OAuth client secrets) – keep them out of code repos and avoid logging them. + +tags_available: + # Relevant technologies and environment tags + - docker + - nodejs + # Data and asset tags + - pii + - auth + - tokens + - logs + - public + - actor + - user + - optional + - proxy + - app + - storage + - volume + - saas + - webhook + # Communication tags + - primary + - direct + - egress + +# ========================= +# DATA ASSETS +# ========================= +data_assets: + + User Accounts: + id: user-accounts + description: "User profile data, credential hashes, emails." + usage: business + tags: ["pii", "auth"] + origin: user-supplied + owner: Lab Owner + quantity: many + confidentiality: confidential + integrity: critical + availability: important + justification_cia_rating: > + Contains personal identifiers and authentication data. High confidentiality is required to protect user privacy, and integrity is critical to prevent account takeovers. + + Orders: + id: orders + description: "Order history, addresses, and payment metadata (no raw card numbers)." + usage: business + tags: ["pii"] + origin: application + owner: Lab Owner + quantity: many + confidentiality: confidential + integrity: important + availability: important + justification_cia_rating: > + Contains users’ personal data and business transaction records. Integrity and confidentiality are important to prevent fraud or privacy breaches. + + Product Catalog: + id: product-catalog + description: "Product information (names, descriptions, prices) available to all users." + usage: business + tags: ["public"] + origin: application + owner: Lab Owner + quantity: many + confidentiality: public + integrity: important + availability: important + justification_cia_rating: > + Product data is intended to be public, but its integrity is important (to avoid defacement or price manipulation that could mislead users). + + Tokens & Sessions: + id: tokens-sessions + description: "Session identifiers, JWTs for authenticated sessions, CSRF tokens." + usage: business + tags: ["auth", "tokens"] + origin: application + owner: Lab Owner + quantity: many + confidentiality: confidential + integrity: important + availability: important + justification_cia_rating: > + If session tokens are compromised, attackers can hijack user sessions. They must be kept confidential and intact; availability is less critical (tokens can be reissued). + + Logs: + id: logs + description: "Application and access logs (may inadvertently contain PII or secrets)." + usage: devops + tags: ["logs"] + origin: application + owner: Lab Owner + quantity: many + confidentiality: internal + integrity: important + availability: important + justification_cia_rating: > + Logs are for internal use (troubleshooting, monitoring). They should not be exposed publicly, and sensitive data should be sanitized to protect confidentiality. + +# ========================= +# TECHNICAL ASSETS +# ========================= +technical_assets: + + User Browser: + id: user-browser + description: "End-user web browser (client)." + type: external-entity + usage: business + used_as_client_by_human: true + out_of_scope: false + justification_out_of_scope: + size: system + technology: browser + tags: ["actor", "user"] + internet: true + machine: virtual + encryption: none + owner: External User + confidentiality: public + integrity: operational + availability: operational + justification_cia_rating: "Client controlled by end user (potentially an attacker)." + multi_tenant: false + redundant: false + custom_developed_parts: false + data_assets_processed: [] + data_assets_stored: [] + data_formats_accepted: + - json + communication_links: + To Reverse Proxy (preferred): + target: reverse-proxy + description: "User browser to reverse proxy (HTTPS on 443)." + protocol: https + authentication: session-id + authorization: enduser-identity-propagation + tags: ["primary"] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - tokens-sessions + data_assets_received: + - product-catalog + Direct to App (no proxy): + target: juice-shop + description: "Direct browser access to app (HTTP on 3000)." + protocol: https + authentication: session-id + authorization: enduser-identity-propagation + tags: ["direct"] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - tokens-sessions + data_assets_received: + - product-catalog + + Reverse Proxy: + id: reverse-proxy + description: "Optional reverse proxy (e.g., Nginx) for TLS termination and adding security headers." + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + justification_out_of_scope: + size: application + technology: reverse-proxy + tags: ["optional", "proxy"] + internet: false + machine: virtual + encryption: transparent + owner: Lab Owner + confidentiality: internal + integrity: important + availability: important + justification_cia_rating: "Not exposed to internet directly; improves security of inbound traffic." + multi_tenant: false + redundant: false + custom_developed_parts: false + data_assets_processed: + - product-catalog + - tokens-sessions + data_assets_stored: [] + data_formats_accepted: + - json + communication_links: + To App: + target: juice-shop + description: "Proxy forwarding to app (HTTP on 3000 internally)." + protocol: https + authentication: none + authorization: none + tags: [] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - tokens-sessions + data_assets_received: + - product-catalog + + Juice Shop Application: + id: juice-shop + description: "OWASP Juice Shop server (Node.js/Express, v19.0.0). Uses parameterized queries to prevent SQLi." + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + justification_out_of_scope: + size: application + technology: web-server + tags: ["app", "nodejs"] + internet: false + machine: container + encryption: none + owner: Lab Owner + confidentiality: internal + integrity: important + availability: important + justification_cia_rating: "In-scope web application (contains all business logic and vulnerabilities by design)." + multi_tenant: false + redundant: false + custom_developed_parts: true + data_assets_processed: + - user-accounts + - orders + - product-catalog + - tokens-sessions + data_assets_stored: + - logs + data_formats_accepted: + - json + communication_links: + To Challenge WebHook: + target: webhook-endpoint + description: "Optional outbound callback (HTTP POST) to external WebHook when a challenge is solved." + protocol: https + authentication: none + authorization: none + tags: ["egress"] + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - orders + + Persistent Storage: + id: persistent-storage + description: "Host-mounted volume for database, file uploads, and logs." + type: datastore + usage: devops + used_as_client_by_human: false + out_of_scope: false + justification_out_of_scope: + size: component + technology: file-server + tags: ["storage", "volume"] + internet: false + machine: virtual + encryption: data-with-symmetric-shared-key + owner: Lab Owner + confidentiality: internal + integrity: important + availability: important + justification_cia_rating: "Local disk storage for the container – not directly exposed, but if compromised it contains sensitive data (database and logs)." + multi_tenant: false + redundant: false + custom_developed_parts: false + data_assets_processed: [] + data_assets_stored: + - logs + - user-accounts + - orders + - product-catalog + data_formats_accepted: + - file + communication_links: {} + + Webhook Endpoint: + id: webhook-endpoint + description: "External WebHook service (3rd-party, if configured for integrations)." + type: external-entity + usage: business + used_as_client_by_human: false + out_of_scope: true + justification_out_of_scope: "Third-party service to receive notifications (not under our control)." + size: system + technology: web-service-rest + tags: ["saas", "webhook"] + internet: true + machine: virtual + encryption: none + owner: Third-Party + confidentiality: internal + integrity: operational + availability: operational + justification_cia_rating: "External service that receives data (like order or challenge info). Treated as a trusted integration point but could be abused if misconfigured." + multi_tenant: true + redundant: true + custom_developed_parts: false + data_assets_processed: + - orders + data_assets_stored: [] + data_formats_accepted: + - json + communication_links: {} + +# ========================= +# TRUST BOUNDARIES +# ========================= +trust_boundaries: + + Internet: + id: internet + description: "Untrusted public network (Internet)." + type: network-dedicated-hoster + tags: [] + technical_assets_inside: + - user-browser + - webhook-endpoint + trust_boundaries_nested: + - host + + Host: + id: host + description: "Local host machine / VM running the Docker environment." + type: network-dedicated-hoster + tags: [] + technical_assets_inside: + - reverse-proxy + - persistent-storage + trust_boundaries_nested: + - container-network + + Container Network: + id: container-network + description: "Docker container network (isolated internal network for containers)." + type: network-dedicated-hoster + tags: [] + technical_assets_inside: + - juice-shop + trust_boundaries_nested: [] + +# ========================= +# SHARED RUNTIMES +# ========================= +shared_runtimes: + + Docker Host: + id: docker-host + description: "Docker Engine and default bridge network on the host." + tags: ["docker"] + technical_assets_running: + - juice-shop + # If the reverse proxy is containerized, include it: + # - reverse-proxy + +# ========================= +# INDIVIDUAL RISK CATEGORIES (optional) +# ========================= +individual_risk_categories: {} + +# ========================= +# RISK TRACKING (optional) +# ========================= +risk_tracking: {} + +# (Optional diagram layout tweaks can be added here) +#diagram_tweak_edge_layout: spline +#diagram_tweak_layout_left_to_right: true diff --git a/submissions/lab2.md b/submissions/lab2.md new file mode 100644 index 000000000..f67dadfb6 --- /dev/null +++ b/submissions/lab2.md @@ -0,0 +1,73 @@ +## Task 1: Baseline Threat Model + +### Risk count by severity +| Severity | Count | +|----------|------:| +| Critical | 0 | +| High | 0 | +| Elevated | 4 | +| Medium | 14 | +| Low | 5 | +| **Total** | 23 | + +### Top 5 risks (paste from `jq` output) +1. **cross-site-scripting** — Cross-Site Scripting (XSS) risk at Juice Shop Application; severity elevated; affecting juice-shop +2. **unencrypted-communication** — Unencrypted Communication named Direct to App (no proxy) between User Browser and Juice Shop Application transferring authentication data; severity elevated; affecting user-browser +3. **unencrypted-communication** — Unencrypted Communication named To App between Reverse Proxy and Juice Shop Application; severity elevated; affecting reverse-proxy +4. **missing-authentication** — Missing Authentication covering communication link To App from Reverse Proxy to Juice Shop Application; severity elevated; affecting juice-shop +5. **missing-waf** — Missing Web Application Firewall (WAF) risk at Juice Shop Application; severity low; affecting juice-shop + +### STRIDE mapping (Lecture 2 slide 7) +- Risk 1: **S (Spoofing) / I (Information Disclosure)** — An attacker can inject malicious scripts into the application to steal user session tokens or spoof actions on behalf of the victim. +- Risk 2: **I (Information Disclosure)** — Transferring authentication data over an unencrypted HTTP link exposes credentials to network eavesdropping and Man-in-the-Middle (MitM) attacks. +- Risk 3: **I (Information Disclosure)** — Lack of encryption on internal traffic between the reverse proxy and the application allows lateral attackers to sniff sensitive data in transit. +- Risk 4: **S (Spoofing) / E (Elevation of Privilege)** — If an attacker bypasses the reverse proxy, they can directly interact with the backend application without authentication, spoofing requests. +- Risk 5: **T (Tampering) / D (Denial of Service)** — Without a WAF filtering malicious incoming traffic, the application is directly exposed to automated tampering payloads and application-layer DoS attacks. + +### Trust boundary observation +The communication link "Direct to App (no proxy)" from the **User Browser** to the **Juice Shop Application** crosses the trust boundary from the completely untrusted public Internet into the application environment. This arrow is particularly attractive to an attacker because it represents the primary, publicly accessible attack surface that can be probed globally without requiring prior internal network compromise. + +## Task 2: Secure Variant & Diff + +### Risk count comparison +| Severity | Baseline | Secure | Δ | +|----------|---------:|-------:|--:| +| Critical | 0 | 0 | 0 | +| High | 0 | 0 | 0 | +| Elevated | 4 | 2 | -2 | +| Medium | 14 | 13 | -1 | +| Low | 5 | 5 | 0 | +| **Total** | 23 | 20 | -3 | + +### Which rules are GONE in the secure variant? +1. `unencrypted-communication` (User Browser to Juice Shop) — fixed by enforcing `https` protocol on the public communication link. +2. `unencrypted-communication` (Reverse Proxy to Juice Shop) — fixed by enforcing `https` on the internal backend link. +3. `unencrypted-asset` (or similar missing at-rest protection) — fixed by applying `data-with-symmetric-shared-key` encryption to the Persistent Storage. + +### Which rules are STILL THERE in the secure variant? +1. `cross-site-scripting` — Architectural hardening (like TLS and encrypted disks) does not fix application-layer vulnerabilities in the source code. +2. `missing-waf` — We did not introduce a Web Application Firewall component into the trust boundary to filter malicious payloads. + +### Honesty check +Did the total drop more than 50%? **No.** The total risk count only dropped from 23 to 20 (a ~13% reduction). +If yes, what does that say about the cost-benefit of these particular hardening changes vs. the work you'd need to fully eliminate the rest? +*Answer:* This demonstrates a classic security reality. Infrastructure hardening (TLS, encrypted volumes) is quick to implement but only stops network sniffing and physical disk theft. It does absolutely nothing against the application-layer flaws (OWASP Top 10) that make up the vast majority of Juice Shop's attack surface. To eliminate the rest, significant effort is required in SAST/DAST scanning and actual code refactoring. + +## Bonus Task: Auth Flow Threat Model + +### Risk count +| Severity | Count | +|----------|------:| +| Elevated | 6 | +| Medium | 20 | +| Low | 10 | +| **Total** | 36 | + +### Three auth-specific risks +1. **unguarded-access-from-internet** (Auth API / Login Link) — STRIDE: **E** (Elevation of Privilege) / **S** (Spoofing) — Mitigation: Implement strict rate limiting, CAPTCHA, or account lockouts to prevent brute-force attacks on the exposed login endpoint. +2. **cross-site-request-forgery** (Admin API via Admin Access Link) — STRIDE: **S** (Spoofing) — Mitigation: Enforce strict SameSite cookie policies for session tokens and require anti-CSRF tokens for all state-changing administrative requests. +3. **missing-authentication-second-factor** (Admin Access Link) — STRIDE: **E** (Elevation of Privilege) — Mitigation: Require Multi-Factor Authentication (MFA/2FA) for any user role attempting to access the highly privileged Admin API. + +### Reflection +What did building the focused model surface that the baseline architecture model missed? +*Answer:* The focused model surfaced deep logical and protocol-level vulnerabilities (like CSRF and the lack of MFA for admin endpoints) that were completely obscured in the baseline model. Architecture-level models highlight infrastructure flaws (like missing TLS), but feature-level models are required to identify business logic and authentication weaknesses.