diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 79b9477e8..000000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,17 +0,0 @@ -## Pull Request Template - -## Goal -One-sentence description of what this PR delivers. - -## Changes -- List files added or modified - -## Testing -- Commands run and observed output - -## Artifacts & Screenshots -- Links to submission files and images - -- [ ] Title uses `feat(labN): ` style -- [ ] No secrets/large temp files committed -- [ ] `submissions/labN.md` present \ No newline at end of file diff --git a/labs/lab2/threagile-model-auth.yaml b/labs/lab2/threagile-model-auth.yaml new file mode 100644 index 000000000..22cdcd368 --- /dev/null +++ b/labs/lab2/threagile-model-auth.yaml @@ -0,0 +1,228 @@ +threagile_version: 1.0.0 +title: Juice Shop Auth Focused Model +date: 2026-06-10 +management_summary_comment: > + Focused model for authentication flow used in Lab 2 bonus task. + +business_criticality: important + +data_assets: + credentials: + id: credentials + description: "Username and password credentials submitted by users." + usage: business + owner: Lab Student + quantity: few + confidentiality: restricted + integrity: operational + availability: operational + justification_cia_rating: "Credentials are sensitive and need protection." + jwt-token: + id: jwt-token + description: "JWT issued by the auth service and used for API calls." + usage: business + owner: Lab Student + quantity: few + confidentiality: internal + integrity: operational + availability: operational + justification_cia_rating: "Tokens grant access and must be protected." + user-session: + id: user-session + description: "Session state stored by the auth/API for logged-in users." + usage: business + owner: Lab Student + quantity: many + confidentiality: internal + integrity: operational + availability: operational + justification_cia_rating: "Session state is needed for authentication continuity." + + refresh-token: + id: refresh-token + description: "Long-lived refresh tokens used to obtain new JWTs without re-authentication." + usage: business + owner: Lab Student + quantity: few + confidentiality: restricted + integrity: important + availability: operational + justification_cia_rating: "Refresh tokens allow session continuation and must be protected and stored securely." + +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 + size: system + technology: browser + tags: [] + internet: true + machine: virtual + encryption: none + owner: Lab Student + confidentiality: public + integrity: operational + availability: operational + justification_cia_rating: "Client controlled by end user." + data_assets_processed: + - credentials + communication_links: + Browser->Auth: + target: auth-api + description: "User submits credentials to Auth API (login/register)." + protocol: https + authentication: none + authorization: none + usage: business + data_assets_sent: + - credentials + data_assets_received: + - jwt-token + + Auth API: + id: auth-api + description: "Authentication API endpoint (issues JWTs)." + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + size: application + technology: web-service-rest + tags: [] + internet: false + machine: container + encryption: none + owner: Lab Student + confidentiality: internal + integrity: important + availability: important + justification_cia_rating: "Auth API handles authentication flows." + data_assets_processed: + - credentials + - jwt-token + communication_links: + Auth->TokenSigner: + target: token-signer + description: "Requests JWT signing from the token service." + protocol: https + authentication: none + authorization: technical-user + usage: business + data_assets_sent: + - jwt-token + Auth->UserDB: + target: user-db + description: "Verify credentials against user database using parameterized queries." + protocol: jdbc-encrypted + authentication: credentials + authorization: technical-user + usage: business + data_assets_sent: + - credentials + + Token Signer: + id: token-signer + description: "Service that issues and verifies JWTs (holds signing keys)." + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + size: component + technology: web-service-rest + tags: [] + internet: false + machine: container + encryption: none + owner: Lab Student + confidentiality: confidential + integrity: critical + availability: operational + justification_cia_rating: "Holds signing keys; high integrity requirement." + data_assets_processed: + - jwt-token + - refresh-token + + User DB: + id: user-db + description: "Database storing user credential hashes and profile data." + type: datastore + usage: devops + used_as_client_by_human: false + out_of_scope: false + size: component + technology: database + tags: [] + internet: false + machine: virtual + encryption: data-with-symmetric-shared-key + owner: Lab Student + confidentiality: restricted + integrity: important + availability: important + justification_cia_rating: "Contains credential hashes and PII." + data_assets_stored: + - credentials + - refresh-token + + Admin Endpoint: + id: admin-endpoint + description: "Admin UI/API that requires admin-role via JWT." + type: process + usage: business + used_as_client_by_human: false + out_of_scope: false + size: application + technology: web-service-rest + tags: [] + internet: false + machine: container + encryption: none + owner: Lab Student + confidentiality: restricted + integrity: important + availability: important + justification_cia_rating: "Admin functions require elevated protection." + communication_links: + Admin->TokenSigner: + target: token-signer + description: "Token verification requests." + protocol: https + authentication: token + authorization: enduser-identity-propagation + usage: business + Admin->UserDB: + target: user-db + description: "Admin queries to inspect or manage user records." + protocol: jdbc-encrypted + authentication: token + authorization: admin-role + usage: business + +trust_boundaries: + Internet: + id: internet + description: "Untrusted public network." + type: network-dedicated-hoster + technical_assets_inside: + - user-browser + + Container Network: + id: container-network + description: "Container network hosting services." + type: network-dedicated-hoster + technical_assets_inside: + - auth-api + - token-signer + - user-db + - admin-endpoint + +shared_runtimes: {} + +# Minimal metadata +name: Juice Shop Auth Flow (focused) +version: 1.0 diff --git a/labs/lab2/threagile-model-secure.yaml b/labs/lab2/threagile-model-secure.yaml new file mode 100644 index 000000000..9a708907d --- /dev/null +++ b/labs/lab2/threagile-model-secure.yaml @@ -0,0 +1,446 @@ +threagile_version: 1.0.0 + +title: OWASP Juice Shop — Local Lab Threat 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 (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 on 3000 internally)." + protocol: https + authentication: session-id + authorization: technical-user + 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: data-with-symmetric-shared-key + 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 + To DB: + target: persistent-storage + description: "App uses prepared statements / parameterized queries when accessing the database." + protocol: jdbc-encrypted + authentication: credentials + authorization: technical-user + vpn: false + ip_filtered: false + readonly: false + usage: business + data_assets_sent: + - user-accounts + - orders + - product-catalog + - tokens-sessions + data_assets_received: + - logs + + 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: none + 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/labs/submissions/lab2.md b/labs/submissions/lab2.md new file mode 100644 index 000000000..e69de29bb diff --git a/submissions/lab2.md b/submissions/lab2.md new file mode 100644 index 000000000..86c2c3af3 --- /dev/null +++ b/submissions/lab2.md @@ -0,0 +1,86 @@ +# Lab 2 Submission + +## Task 1: Baseline Threat Model + +### Risk count by severity +| Severity | Count | +|----------|------:| +| Elevated | 4 | +| Medium | 14 | +| Low | 5 | +| **Total** | **23** | + +### Top 5 risks (paste from `jq` output) +1. **unencrypted-asset@juice-shop** — Unencrypted Technical Asset named Juice Shop Application; severity medium; affecting `juice-shop` +2. **unencrypted-asset@persistent-storage** — Unencrypted Technical Asset named Persistent Storage; severity medium; affecting `persistent-storage` +3. **missing-identity-store@reverse-proxy** — Missing Identity Store in the threat model (example asset Reverse Proxy); severity medium; affecting `reverse-proxy` +4. **missing-authentication@reverse-proxy>to-app@reverse-proxy@juice-shop** — Missing Authentication covering communication link To App from Reverse Proxy to Juice Shop Application; severity elevated; affecting `juice-shop` +5. **cross-site-request-forgery@juice-shop@user-browser>direct-to-app-no-proxy** — Cross-Site Request Forgery risk involving the Direct-to-App (no proxy) path; severity medium; affecting `juice-shop` + +### STRIDE mapping (Lecture 2 slide 7) +- missing-authentication: **A** — attacker can bypass authentication on the app-facing reverse-proxy link. +- cross-site-request-forgery: **S** — an attacker can cause a user's browser to perform actions without their intent, effectively acting as the user. +- unencrypted communication (Direct to App): **I/D** — unprotected traffic can be intercepted (Disclosure) or modified (Tampering). +- unencrypted communication (To App): **I/D** — internal HTTP traffic exposes session/token traffic in the container network to interception or modification. +- unencrypted asset (Juice Shop Application / Persistent Storage): **D** — the asset is not encrypted and sensitive data can be disclosed if accessed. + +### Trust boundary observation +The `Direct to App (no proxy)` arrow crosses the untrusted Internet trust boundary directly into `Juice Shop Application`. This path is attractive because it bypasses the reverse proxy controls and exposes authentication/session data to attackers. + +## Task 2: Secure Variant & Diff + +### Risk count comparison +| Severity | Baseline | Secure | Δ | +|----------|---------:|-------:|--:| +| Critical | 0 | 0 | 0 | +| High | 0 | 0 | 0 | +| Elevated | 4 | 3 | -1 | +| Medium | 14 | 13 | -1 | +| Low | 5 | 5 | 0 | +| **Total** | **23** | **21** | **-2** | + +The secure variant was implemented by hardening `Direct to App (no proxy)` and `To App` to HTTPS, enabling encryption on `Persistent Storage`, and adding a database access link with prepared-statement documentation in the description. + + +### Which rules are GONE in the secure variant? +1. `unencrypted-communication@user-browser>direct-to-app-no-proxy@user-browser@juice-shop` — fixed by switching direct browser-to-app traffic to `protocol: https`. +2. `unencrypted-communication@reverse-proxy>to-app@reverse-proxy@juice-shop` — fixed by changing the proxy→app link to `protocol: https` and adding link-level authentication. +3. `missing-authentication@reverse-proxy>to-app@reverse-proxy@juice-shop` — fixed by introducing authentication/authorization controls on the reverse-proxy→app communication link. + +### Which rules are STILL THERE in the secure variant? +1. `cross-site-scripting@juice-shop` — The application still processes untrusted input in contexts that allow script execution; transport and storage improvements do not eliminate injection vulnerabilities. Fixing this requires code changes (input validation and output encoding) and runtime policies such as a Content Security Policy to reduce impact. + +2. `missing-identity-store@reverse-proxy` — The model still lacks a centralized identity store, so identity lifecycle and authoritative authentication are not enforced by design. Introducing an identity provider and integrating it into the architecture is required to address this risk, which is a larger design change beyond simple configuration. + +### Honesty check +No — the total risk count dropped only slightly (from 23 to 21, ~8.7%), which is well below a 50% reduction. This indicates that the targeted hardening steps (HTTPS, storage encryption, database access controls) produced modest improvements for transport and storage risks, but many remaining risks are application-level and require more invasive work (code fixes, identity integration, build hardening) with higher development cost. The cost-benefit therefore favors pairing infrastructure hardening with prioritized application fixes rather than attempting to eliminate all risks through infrastructure changes alone. + +## Bonus Task: Auth Flow Threat Model + +### Risk count +| Severity | Count | +|----------|------:| +| Critical | 0 | +| High | 0 | +| Elevated | 1 | +| Medium | 11 | +| Low | 6 | +| **Total** | **18** | + +### Three auth-specific risks (NOT in the baseline model's top 5) +For each, name: +- The rule ID Threagile fires +- The STRIDE letter +- A 1-2 sentence mitigation in plain English + +1. **sql-nosql-injection@auth-api@user-db@auth-api>auth-userdb** — STRIDE: T — Mitigation: Use parameterized queries / prepared statements and validate input strictly on the Auth API. Additionally, run the Auth API with a least-privilege DB account and restrict DB permissions to only what's necessary. + +2. **missing-identity-store@token-signer** — STRIDE: S — Mitigation: Introduce a centralized identity provider or identity store to manage credentials and identity lifecycle for the authentication components. Integrate service authentication and rotate credentials centrally so tokens and keys are managed and audited. + +3. **missing-authentication@auth-api>auth-tokensigner@auth-api@token-signer** — STRIDE: S — Mitigation: Require authenticated, authorized service-to-service calls (for example mTLS or signed service tokens) between the Auth API and the Token Signer, and enforce authorization checks. Also restrict network access so only the Auth API can reach the Token Signer. + +### Reflection (2-3 sentences) +Building a focused auth model revealed that many high-impact risks concentrate around credential handling, token issuance, and database access. Infrastructure hardening alone is insufficient; secure authentication needs careful design (identity stores, authenticated service-to-service calls, parameterized DB access) and code-level fixes to fully mitigate these risks. + + +