diff --git a/labs/lab2/threagile-model-auth.yaml b/labs/lab2/threagile-model-auth.yaml new file mode 100644 index 000000000..aa075807a --- /dev/null +++ b/labs/lab2/threagile-model-auth.yaml @@ -0,0 +1,286 @@ +threagile_version: 0.9.1 + +title: OWASP Juice Shop — Authentication Threat Model + +date: 2026-06-10 + +author: + name: Semen Nadutkin + homepage: https://github.com/semyonnadutkin + +management_summary_comment: > + Minimal authentication and authorization threat model for OWASP Juice Shop. + The model focuses on credential handling, JWT issuance and verification, + session management, and authorization of administrative operations. + +business_criticality: important + +questions: {} + +tags_available: + - auth + - jwt + +data_assets: + + Credentials: + id: credentials + description: Username and password used for authentication + usage: business + origin: Browser + owner: Users + quantity: many + confidentiality: strictly-confidential + integrity: critical + availability: important + + JWT Token: + id: jwt-token + description: Signed JWT used for authenticated requests + usage: business + origin: Token Signer + owner: Juice Shop + quantity: many + confidentiality: confidential + integrity: mission-critical + availability: important + + User Session State: + id: session-state + description: Authenticated user session information + usage: business + origin: Auth API + owner: Juice Shop + quantity: many + confidentiality: confidential + integrity: critical + availability: important + + Admin Operation Requests: + id: admin-operations + description: Requests performing privileged administrative actions + usage: business + origin: Browser + owner: Administrators + quantity: many + confidentiality: internal + integrity: mission-critical + availability: important + + JWT Signing Keys: + id: jwt-signing-keys + description: Secret keys used to sign and verify JWT tokens + usage: business + origin: Token Signer + owner: Juice Shop + quantity: few + confidentiality: strictly-confidential + integrity: mission-critical + availability: critical + +trust_boundaries: + + Internet: + id: internet + description: Untrusted external network + type: network-cloud-provider + + Container: + id: container + description: Internal application environment + type: execution-environment + +technical_assets: + + Browser: + id: browser + description: User web browser + type: external-entity + usage: business + size: system + technology: browser + machine: virtual + encryption: transparent + internet: true + multi_tenant: false + redundant: false + custom_developed_parts: false + out_of_scope: false + owner: User + confidentiality: confidential + integrity: operational + availability: operational + data_assets_processed: + - credentials + - jwt-token + - admin-operations + + communication_links: + + Login and Registration: + target: auth-api + protocol: https + usage: business + authentication: none + authorization: none + data_assets_sent: + - credentials + + Authenticated Requests: + target: auth-api + protocol: https + usage: business + authentication: token + authorization: enduser-identity-propagation + data_assets_sent: + - jwt-token + + Admin Requests: + target: admin-endpoint + protocol: https + usage: business + authentication: token + authorization: enduser-identity-propagation + data_assets_sent: + - jwt-token + - admin-operations + + Auth API: + id: auth-api + description: Juice Shop authentication endpoint + type: process + usage: business + size: service + technology: web-application + machine: container + encryption: data-with-symmetric-shared-key + internet: false + multi_tenant: false + redundant: true + custom_developed_parts: true + out_of_scope: false + owner: Juice Shop + confidentiality: confidential + integrity: critical + availability: important + + data_assets_processed: + - credentials + - session-state + - jwt-token + + data_assets_stored: + - session-state + + communication_links: + + Credential Lookup: + target: user-db + protocol: jdbc-encrypted + usage: business + authentication: credentials + authorization: technical-user + data_assets_sent: + - credentials + + Request JWT: + target: token-signer + protocol: https + usage: business + authentication: credentials + authorization: technical-user + data_assets_sent: + - credentials + data_assets_received: + - jwt-token + + Verify JWT: + target: token-signer + protocol: https + usage: business + authentication: credentials + authorization: technical-user + data_assets_sent: + - jwt-token + + Token Signer: + id: token-signer + description: JWT signing and verification component + type: process + usage: business + size: service + technology: identity-provider + machine: container + encryption: data-with-symmetric-shared-key + internet: false + multi_tenant: false + redundant: true + custom_developed_parts: true + out_of_scope: false + owner: Juice Shop + confidentiality: strictly-confidential + integrity: mission-critical + availability: important + + data_assets_processed: + - jwt-token + - jwt-signing-keys + + data_assets_stored: + - jwt-signing-keys + + User DB: + id: user-db + description: Credential store + type: datastore + usage: business + size: service + technology: database + machine: container + encryption: data-with-symmetric-shared-key + internet: false + multi_tenant: false + redundant: true + custom_developed_parts: false + out_of_scope: false + owner: Juice Shop + confidentiality: strictly-confidential + integrity: critical + availability: important + + data_assets_stored: + - credentials + + Admin Endpoint: + id: admin-endpoint + description: Administrative API endpoint + type: process + usage: business + size: service + technology: web-application + machine: container + encryption: data-with-symmetric-shared-key + internet: false + multi_tenant: false + redundant: true + custom_developed_parts: true + out_of_scope: false + owner: Juice Shop + confidentiality: confidential + integrity: mission-critical + availability: important + + data_assets_processed: + - jwt-token + - admin-operations + + communication_links: + + Verify JWT And Role: + target: token-signer + protocol: https + usage: business + authentication: credentials + authorization: technical-user + data_assets_sent: + - jwt-token diff --git a/labs/lab2/threagile-model-secure.yaml b/labs/lab2/threagile-model-secure.yaml new file mode 100644 index 000000000..d76b031a1 --- /dev/null +++ b/labs/lab2/threagile-model-secure.yaml @@ -0,0 +1,429 @@ +threagile_version: 1.0.0 + +title: OWASP Juice Shop — Local Lab Threat Model +date: 2025-09-18 + +author: + name: Semen Nadutkin + homepage: https://github.com/semyonnadutkin + +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 (HTTPS 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 (HTTPS internally). The app uses parameterized queries" + protocol: https + authentication: token + 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)." + 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..ab84c6f7d --- /dev/null +++ b/submissions/lab2.md @@ -0,0 +1,80 @@ +## 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. **missing-authentication** — Missing Authentication covering communication link *To App* from Reverse Proxy to Juice Shop Application; severity **elevated**; affecting **juice-shop** +3. **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** +4. **unencrypted-communication** — Unencrypted Communication named *To App* between Reverse Proxy and Juice Shop Application; severity **elevated**; affecting **reverse-proxy** +5. **container-baseimage-backdooring** — Container Base Image Backdooring risk at Juice Shop Application; severity **medium**; affecting **juice-shop** + + +### STRIDE mapping (Lecture 2 slide 7) +For each top-5 risk, name the STRIDE letter(s) it primarily violates: +- Risk 1: **I, E** — XSS can steal user data and be executed with another user's privileges. +- Risk 2: **S, E** — an attacker can impersonate legitimate components and gain another's user privileges. +- Risk 3: **I** — without encryption, an attacker _(e.g. MITM)_ can steal user data. +- Risk 4: **I** — an attacker can read all traffic between the reverse proxy and the application. +- Risk 5: **T, E** — a backdoored container base image can be modified by an attacker, leading to malicious code execution and privilege escalation inside the application environment. + +### Trust boundary observation +Looking at `data-flow-diagram.png`, name one arrow crossing a trust boundary that +appears in your top-5 risks. Why is that arrow particularly attractive to an attacker? + +Looking at `data-flow-diagram.png`, the direct arrow from User Browser to Juice Shop Application appears in the top-5 risks above _(risk 4)_. The arrow is "particularly attractive to an attacker" since it is easy to steal sensitive user data _(passwords, credit card numbers, etc.)_: an attacker, being a transport node on the route between the user and the application _(e.g. ISP)_ can eavesdrop on the data. + +## Task 2: Secure Variant & Diff + +### Risk count comparison +| Severity | Baseline | Secure | Δ | +|----------|---------:|-------:|--:| +| Critical | 0 | 0 | 0 | +| High | 0 | 0 | 0 | +| Elevated | 4 | 1 | -3 | +| Medium | 14 | 13 | -1 | +| Low | 5 | 5 | 0 | +| **Total** | 23 | 19 | -4 | + +### Which rules are GONE in the secure variant? +1. **missing-authentication** — fixed by changing `authentication: none` to `authentication: token` in technical asset **"Reverse Proxy"**, communication link **"To App"**. +2. **unencrypted-communication** _(Reverse Proxy to App)_ — fixed by changing `protocol: http` to `protocol: https` in technical asset **"Reverse Proxy"**, communication link **"To App"**. +3. **unencrypted-communication** _(Direct to App (no proxy))_ — fixed by changing `protocol: http` to `protocol: https` in technical asset **"User Browser"**, communication link **"Direct to App (no proxy)"**. + +### Which rules are STILL THERE in the secure variant? +1. **cross-site-scripting** — the risk remains because the implemented changes focused on transport security, encryption, and secure communication links, not on eliminating application-layer input validation flaws. OWASP Juice Shop is intentionally vulnerable by design, so user-supplied content may still be rendered in a way that allows malicious JavaScript execution. Security headers and TLS reduce the impact of some attacks but do not completely prevent XSS vulnerabilities in the application code. + +2. **container-baseimage-backdooring** — the risk remains because the threat model still relies on a Docker container image whose supply chain is outside the scope of the implemented mitigations. Encrypting data, enforcing HTTPS, and securing network communication do not verify the integrity or trustworthiness of the container base image itself. A compromised or malicious base image could still introduce backdoors into the application environment before deployment. + +### Honesty check +The total number of risks dropped by approximately 17.39% (from 23 to 19). The implemented hardening measures primarily addressed transport and storage security concerns, while the remaining findings are mostly related to application-level vulnerabilities and software supply-chain risks that require secure coding practices, stronger input validation, dependency management, and image provenance controls. Despite the relatively small reduction in the total risk count, the changes were effective in removing 3 of the 4 elevated-severity risks, indicating a favorable security improvement for a comparatively low implementation effort. + +## Bonus Task: Auth Flow Threat Model + +### Risk count +| Severity | Count | +|----------|------:| +| Critical | 0 | +| High | 1 | +| Elevated | 18 | +| Medium | 12 | +| Low | 1 | +| **Total** | 32 | + +### Three auth-specific risks (NOT in the baseline model's top 5) +1. **missing-identity-provider-isolation** — STRIDE: E — Mitigation: Place the Token Signer into a dedicated network segment and allow access only from the trusted services. +2. **missing-vault** — STRIDE: E — Mitigation: Store JWT signing keys in a dedicated Vault or use a Secret Manager. +3. **missing-identity-store** — STRIDE: S — Mitigation: Implement a dedicated identity store. + +### Reflection +The focused model revealed authentication-specific risks that were not visible in the baseline architecture model, such as missing identity provider isolation, lack of secure vault for JWT signing keys, and absence of a dedicated identity store. + +By decomposing authentication into concrete components _(`JWT token`, `User Session state`, `Admin operation requests`, etc.)_, the model introduced explicit trust boundaries and data flows. This allowed Threagile to detect implementation-level risks related to token handling and identity management that are not apparent in a high-level architectural view. \ No newline at end of file