diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000..2b51ab46 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,28 @@ +## Goal + + +## Changes + +- +- +- + +## Testing + +- [ ] Application runs locally +- [ ] Commands executed successfully +- [ ] Documentation reviewed for accuracy + +## Artifacts & Screenshots + +- Screenshots: + - + - + +--- + +### Checklist +- [ ] PR title is clear and descriptive +- [ ] Documentation updated (if applicable) +- [ ] No secrets, credentials, or large temporary files committed + diff --git a/labs/lab2/baseline/data-asset-diagram.png b/labs/lab2/baseline/data-asset-diagram.png new file mode 100644 index 00000000..4457d768 Binary files /dev/null and b/labs/lab2/baseline/data-asset-diagram.png differ diff --git a/labs/lab2/baseline/data-flow-diagram.png b/labs/lab2/baseline/data-flow-diagram.png new file mode 100644 index 00000000..a8803816 Binary files /dev/null and b/labs/lab2/baseline/data-flow-diagram.png differ diff --git a/labs/lab2/baseline/report.pdf b/labs/lab2/baseline/report.pdf new file mode 100644 index 00000000..369376fe Binary files /dev/null and b/labs/lab2/baseline/report.pdf differ diff --git a/labs/lab2/baseline/risks.json b/labs/lab2/baseline/risks.json new file mode 100644 index 00000000..7e917d5d --- /dev/null +++ b/labs/lab2/baseline/risks.json @@ -0,0 +1,410 @@ +[ + { + "category": "missing-hardening", + "risk_status": "unchecked", + "severity": 2, + "exploitation_likelihood": 3, + "exploitation_impact": 1, + "title": "Missing Hardening risk at Juice Shop Application", + "synthetic_id": "missing-hardening@juice-shop", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "juice-shop", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "", + "data_breach_probability": "improbable", + "data_breach_technical_assets": [ + "juice-shop" + ] + }, + { + "category": "missing-hardening", + "risk_status": "unchecked", + "severity": 2, + "exploitation_likelihood": 3, + "exploitation_impact": 1, + "title": "Missing Hardening risk at Persistent Storage", + "synthetic_id": "missing-hardening@persistent-storage", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "persistent-storage", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "", + "data_breach_probability": "improbable", + "data_breach_technical_assets": [ + "persistent-storage" + ] + }, + { + "category": "missing-build-infrastructure", + "risk_status": "unchecked", + "severity": 2, + "exploitation_likelihood": 1, + "exploitation_impact": 2, + "title": "Missing Build Infrastructure in the threat model (referencing asset Juice Shop Application as an example)", + "synthetic_id": "missing-build-infrastructure@juice-shop", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "juice-shop", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "", + "data_breach_probability": "improbable", + "data_breach_technical_assets": [] + }, + { + "category": "server-side-request-forgery", + "risk_status": "unchecked", + "severity": 2, + "exploitation_likelihood": 3, + "exploitation_impact": 1, + "title": "Server-Side Request Forgery (SSRF) risk at Juice Shop Application server-side web-requesting the target Webhook Endpoint via To Challenge WebHook", + "synthetic_id": "server-side-request-forgery@juice-shop@webhook-endpoint@juice-shop>to-challenge-webhook", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "juice-shop", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "juice-shop>to-challenge-webhook", + "data_breach_probability": 2, + "data_breach_technical_assets": [ + "juice-shop" + ] + }, + { + "category": "server-side-request-forgery", + "risk_status": "unchecked", + "severity": 2, + "exploitation_likelihood": 3, + "exploitation_impact": 1, + "title": "Server-Side Request Forgery (SSRF) risk at Reverse Proxy server-side web-requesting the target Juice Shop Application via To App", + "synthetic_id": "server-side-request-forgery@reverse-proxy@juice-shop@reverse-proxy>to-app", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "reverse-proxy", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "reverse-proxy>to-app", + "data_breach_probability": 2, + "data_breach_technical_assets": [ + "reverse-proxy" + ] + }, + { + "category": "unnecessary-data-transfer", + "risk_status": "unchecked", + "severity": 1, + "exploitation_likelihood": 1, + "exploitation_impact": 1, + "title": "Unnecessary Data Transfer of Tokens & Sessions data at User Browser from/to Juice Shop Application", + "synthetic_id": "unnecessary-data-transfer@tokens-sessions@user-browser@juice-shop", + "most_relevant_data_asset": "tokens-sessions", + "most_relevant_technical_asset": "user-browser", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "", + "data_breach_probability": "improbable", + "data_breach_technical_assets": [ + "user-browser" + ] + }, + { + "category": "unnecessary-data-transfer", + "risk_status": "unchecked", + "severity": 1, + "exploitation_likelihood": 1, + "exploitation_impact": 1, + "title": "Unnecessary Data Transfer of Tokens & Sessions data at User Browser from/to Reverse Proxy", + "synthetic_id": "unnecessary-data-transfer@tokens-sessions@user-browser@reverse-proxy", + "most_relevant_data_asset": "tokens-sessions", + "most_relevant_technical_asset": "user-browser", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "", + "data_breach_probability": "improbable", + "data_breach_technical_assets": [ + "user-browser" + ] + }, + { + "category": "unnecessary-technical-asset", + "risk_status": "unchecked", + "severity": 1, + "exploitation_likelihood": 1, + "exploitation_impact": 1, + "title": "Unnecessary Technical Asset named Persistent Storage", + "synthetic_id": "unnecessary-technical-asset@persistent-storage", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "persistent-storage", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "", + "data_breach_probability": "improbable", + "data_breach_technical_assets": [ + "persistent-storage" + ] + }, + { + "category": "unnecessary-technical-asset", + "risk_status": "unchecked", + "severity": 1, + "exploitation_likelihood": 1, + "exploitation_impact": 1, + "title": "Unnecessary Technical Asset named User Browser", + "synthetic_id": "unnecessary-technical-asset@user-browser", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "user-browser", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "", + "data_breach_probability": "improbable", + "data_breach_technical_assets": [ + "user-browser" + ] + }, + { + "category": "cross-site-scripting", + "risk_status": "unchecked", + "severity": 4, + "exploitation_likelihood": 3, + "exploitation_impact": 2, + "title": "Cross-Site Scripting (XSS) risk at Juice Shop Application", + "synthetic_id": "cross-site-scripting@juice-shop", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "juice-shop", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "", + "data_breach_probability": 2, + "data_breach_technical_assets": [ + "juice-shop" + ] + }, + { + "category": "cross-site-request-forgery", + "risk_status": "unchecked", + "severity": 2, + "exploitation_likelihood": 4, + "exploitation_impact": 1, + "title": "Cross-Site Request Forgery (CSRF) risk at Juice Shop Application via Direct to App (no proxy) from User Browser", + "synthetic_id": "cross-site-request-forgery@juice-shop@user-browser>direct-to-app-no-proxy", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "juice-shop", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "user-browser>direct-to-app-no-proxy", + "data_breach_probability": "improbable", + "data_breach_technical_assets": [ + "juice-shop" + ] + }, + { + "category": "cross-site-request-forgery", + "risk_status": "unchecked", + "severity": 2, + "exploitation_likelihood": 4, + "exploitation_impact": 1, + "title": "Cross-Site Request Forgery (CSRF) risk at Juice Shop Application via To App from Reverse Proxy", + "synthetic_id": "cross-site-request-forgery@juice-shop@reverse-proxy>to-app", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "juice-shop", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "reverse-proxy>to-app", + "data_breach_probability": "improbable", + "data_breach_technical_assets": [ + "juice-shop" + ] + }, + { + "category": "missing-waf", + "risk_status": "unchecked", + "severity": 1, + "exploitation_likelihood": 1, + "exploitation_impact": 1, + "title": "Missing Web Application Firewall (WAF) risk at Juice Shop Application", + "synthetic_id": "missing-waf@juice-shop", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "juice-shop", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "", + "data_breach_probability": "improbable", + "data_breach_technical_assets": [ + "juice-shop" + ] + }, + { + "category": "unencrypted-communication", + "risk_status": "unchecked", + "severity": 4, + "exploitation_likelihood": 3, + "exploitation_impact": 3, + "title": "Unencrypted Communication named Direct to App (no proxy) between User Browser and Juice Shop Application transferring authentication data (like credentials, token, session-id, etc.)", + "synthetic_id": "unencrypted-communication@user-browser>direct-to-app-no-proxy@user-browser@juice-shop", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "user-browser", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "user-browser>direct-to-app-no-proxy", + "data_breach_probability": 2, + "data_breach_technical_assets": [ + "juice-shop" + ] + }, + { + "category": "unencrypted-communication", + "risk_status": "unchecked", + "severity": 4, + "exploitation_likelihood": 3, + "exploitation_impact": 2, + "title": "Unencrypted Communication named To App between Reverse Proxy and Juice Shop Application", + "synthetic_id": "unencrypted-communication@reverse-proxy>to-app@reverse-proxy@juice-shop", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "reverse-proxy", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "reverse-proxy>to-app", + "data_breach_probability": 2, + "data_breach_technical_assets": [ + "juice-shop" + ] + }, + { + "category": "missing-authentication", + "risk_status": "unchecked", + "severity": 4, + "exploitation_likelihood": 3, + "exploitation_impact": 2, + "title": "Missing Authentication covering communication link To App from Reverse Proxy to Juice Shop Application", + "synthetic_id": "missing-authentication@reverse-proxy>to-app@reverse-proxy@juice-shop", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "juice-shop", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "reverse-proxy>to-app", + "data_breach_probability": 2, + "data_breach_technical_assets": [ + "juice-shop" + ] + }, + { + "category": "missing-authentication-second-factor", + "risk_status": "unchecked", + "severity": 2, + "exploitation_likelihood": 1, + "exploitation_impact": 2, + "title": "Missing Two-Factor Authentication covering communication link Direct to App (no proxy) from User Browser to Juice Shop Application", + "synthetic_id": "missing-authentication-second-factor@user-browser>direct-to-app-no-proxy@user-browser@juice-shop", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "juice-shop", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "user-browser>direct-to-app-no-proxy", + "data_breach_probability": 2, + "data_breach_technical_assets": [ + "juice-shop" + ] + }, + { + "category": "missing-authentication-second-factor", + "risk_status": "unchecked", + "severity": 2, + "exploitation_likelihood": 1, + "exploitation_impact": 2, + "title": "Missing Two-Factor Authentication covering communication link To App from User Browser forwarded via Reverse Proxy to Juice Shop Application", + "synthetic_id": "missing-authentication-second-factor@reverse-proxy>to-app@reverse-proxy@juice-shop", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "juice-shop", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "reverse-proxy>to-app", + "data_breach_probability": 2, + "data_breach_technical_assets": [ + "juice-shop" + ] + }, + { + "category": "container-baseimage-backdooring", + "risk_status": "unchecked", + "severity": 2, + "exploitation_likelihood": 1, + "exploitation_impact": 2, + "title": "Container Base Image Backdooring risk at Juice Shop Application", + "synthetic_id": "container-baseimage-backdooring@juice-shop", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "juice-shop", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "", + "data_breach_probability": "probable", + "data_breach_technical_assets": [ + "juice-shop" + ] + }, + { + "category": "unencrypted-asset", + "risk_status": "unchecked", + "severity": 2, + "exploitation_likelihood": 1, + "exploitation_impact": 2, + "title": "Unencrypted Technical Asset named Juice Shop Application", + "synthetic_id": "unencrypted-asset@juice-shop", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "juice-shop", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "", + "data_breach_probability": "improbable", + "data_breach_technical_assets": [ + "juice-shop" + ] + }, + { + "category": "unencrypted-asset", + "risk_status": "unchecked", + "severity": 2, + "exploitation_likelihood": 1, + "exploitation_impact": 2, + "title": "Unencrypted Technical Asset named Persistent Storage", + "synthetic_id": "unencrypted-asset@persistent-storage", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "persistent-storage", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "", + "data_breach_probability": "improbable", + "data_breach_technical_assets": [ + "persistent-storage" + ] + }, + { + "category": "missing-vault", + "risk_status": "unchecked", + "severity": 2, + "exploitation_likelihood": 1, + "exploitation_impact": 2, + "title": "Missing Vault (Secret Storage) in the threat model (referencing asset Juice Shop Application as an example)", + "synthetic_id": "missing-vault@juice-shop", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "juice-shop", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "", + "data_breach_probability": "improbable", + "data_breach_technical_assets": [] + }, + { + "category": "missing-identity-store", + "risk_status": "unchecked", + "severity": 2, + "exploitation_likelihood": 1, + "exploitation_impact": 2, + "title": "Missing Identity Store in the threat model (referencing asset Reverse Proxy as an example)", + "synthetic_id": "missing-identity-store@reverse-proxy", + "most_relevant_data_asset": "", + "most_relevant_technical_asset": "reverse-proxy", + "most_relevant_trust_boundary": "", + "most_relevant_shared_runtime": "", + "most_relevant_communication_link": "", + "data_breach_probability": "improbable", + "data_breach_technical_assets": [] + } +] diff --git a/labs/lab2/baseline/stats.json b/labs/lab2/baseline/stats.json new file mode 100644 index 00000000..88cd78be --- /dev/null +++ b/labs/lab2/baseline/stats.json @@ -0,0 +1 @@ +{"risks":{"critical":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":0},"elevated":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":4},"high":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":0},"low":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":5},"medium":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":14}}} \ No newline at end of file diff --git a/labs/lab2/baseline/technical-assets.json b/labs/lab2/baseline/technical-assets.json new file mode 100644 index 00000000..45457f1e --- /dev/null +++ b/labs/lab2/baseline/technical-assets.json @@ -0,0 +1 @@ +{"juice-shop":{"Id":"juice-shop","Title":"Juice Shop Application","Description":"OWASP Juice Shop server (Node.js/Express, v19.0.0).","Usage":0,"Type":1,"Size":2,"Technology":6,"Machine":2,"Internet":false,"MultiTenant":false,"Redundant":false,"CustomDevelopedParts":true,"OutOfScope":false,"UsedAsClientByHuman":false,"Encryption":0,"JustificationOutOfScope":"","Owner":"Lab Owner","Confidentiality":1,"Integrity":2,"Availability":2,"JustificationCiaRating":"In-scope web application (contains all business logic and vulnerabilities by design).","Tags":["app","nodejs"],"DataAssetsProcessed":["user-accounts","orders","product-catalog","tokens-sessions"],"DataAssetsStored":["logs"],"DataFormatsAccepted":[0],"CommunicationLinks":[{"Id":"juice-shop\u003eto-challenge-webhook","SourceId":"juice-shop","TargetId":"webhook-endpoint","Title":"To Challenge WebHook","Description":"Optional outbound callback (HTTP POST) to external WebHook when a challenge is solved.","Protocol":2,"Tags":["egress"],"VPN":false,"IpFiltered":false,"Readonly":false,"Authentication":0,"Authorization":0,"Usage":0,"DataAssetsSent":["orders"],"DataAssetsReceived":null,"DiagramTweakWeight":1,"DiagramTweakConstraint":true}],"DiagramTweakOrder":0,"RAA":70.02881844380403},"persistent-storage":{"Id":"persistent-storage","Title":"Persistent Storage","Description":"Host-mounted volume for database, file uploads, and logs.","Usage":1,"Type":2,"Size":3,"Technology":10,"Machine":1,"Internet":false,"MultiTenant":false,"Redundant":false,"CustomDevelopedParts":false,"OutOfScope":false,"UsedAsClientByHuman":false,"Encryption":0,"JustificationOutOfScope":"","Owner":"Lab Owner","Confidentiality":1,"Integrity":2,"Availability":2,"JustificationCiaRating":"Local disk storage for the container – not directly exposed, but if compromised it contains sensitive data (database and logs).","Tags":["storage","volume"],"DataAssetsProcessed":[],"DataAssetsStored":["logs","user-accounts","orders","product-catalog"],"DataFormatsAccepted":[3],"CommunicationLinks":[],"DiagramTweakOrder":0,"RAA":100},"reverse-proxy":{"Id":"reverse-proxy","Title":"Reverse Proxy","Description":"Optional reverse proxy (e.g., Nginx) for TLS termination and adding security headers.","Usage":0,"Type":1,"Size":2,"Technology":20,"Machine":1,"Internet":false,"MultiTenant":false,"Redundant":false,"CustomDevelopedParts":false,"OutOfScope":false,"UsedAsClientByHuman":false,"Encryption":1,"JustificationOutOfScope":"","Owner":"Lab Owner","Confidentiality":1,"Integrity":2,"Availability":2,"JustificationCiaRating":"Not exposed to internet directly; improves security of inbound traffic.","Tags":["optional","proxy"],"DataAssetsProcessed":["product-catalog","tokens-sessions"],"DataAssetsStored":[],"DataFormatsAccepted":[0],"CommunicationLinks":[{"Id":"reverse-proxy\u003eto-app","SourceId":"reverse-proxy","TargetId":"juice-shop","Title":"To App","Description":"Proxy forwarding to app (HTTP on 3000 internally).","Protocol":1,"Tags":[],"VPN":false,"IpFiltered":false,"Readonly":false,"Authentication":0,"Authorization":0,"Usage":0,"DataAssetsSent":["tokens-sessions"],"DataAssetsReceived":["product-catalog"],"DiagramTweakWeight":1,"DiagramTweakConstraint":true}],"DiagramTweakOrder":0,"RAA":9.623538157950035},"user-browser":{"Id":"user-browser","Title":"User Browser","Description":"End-user web browser (client).","Usage":0,"Type":0,"Size":0,"Technology":2,"Machine":1,"Internet":true,"MultiTenant":false,"Redundant":false,"CustomDevelopedParts":false,"OutOfScope":false,"UsedAsClientByHuman":true,"Encryption":0,"JustificationOutOfScope":"","Owner":"External User","Confidentiality":0,"Integrity":1,"Availability":1,"JustificationCiaRating":"Client controlled by end user (potentially an attacker).","Tags":["actor","user"],"DataAssetsProcessed":[],"DataAssetsStored":[],"DataFormatsAccepted":[0],"CommunicationLinks":[{"Id":"user-browser\u003eto-reverse-proxy-preferred","SourceId":"user-browser","TargetId":"reverse-proxy","Title":"To Reverse Proxy (preferred)","Description":"User browser to reverse proxy (HTTPS on 443).","Protocol":2,"Tags":["primary"],"VPN":false,"IpFiltered":false,"Readonly":false,"Authentication":2,"Authorization":2,"Usage":0,"DataAssetsSent":["tokens-sessions"],"DataAssetsReceived":["product-catalog"],"DiagramTweakWeight":1,"DiagramTweakConstraint":true},{"Id":"user-browser\u003edirect-to-app-no-proxy","SourceId":"user-browser","TargetId":"juice-shop","Title":"Direct to App (no proxy)","Description":"Direct browser access to app (HTTP on 3000).","Protocol":1,"Tags":["direct"],"VPN":false,"IpFiltered":false,"Readonly":false,"Authentication":2,"Authorization":2,"Usage":0,"DataAssetsSent":["tokens-sessions"],"DataAssetsReceived":["product-catalog"],"DiagramTweakWeight":1,"DiagramTweakConstraint":true}],"DiagramTweakOrder":0,"RAA":25.859639506459924},"webhook-endpoint":{"Id":"webhook-endpoint","Title":"Webhook Endpoint","Description":"External WebHook service (3rd-party, if configured for integrations).","Usage":0,"Type":0,"Size":0,"Technology":14,"Machine":1,"Internet":true,"MultiTenant":true,"Redundant":true,"CustomDevelopedParts":false,"OutOfScope":true,"UsedAsClientByHuman":false,"Encryption":0,"JustificationOutOfScope":"Third-party service to receive notifications (not under our control).","Owner":"Third-Party","Confidentiality":1,"Integrity":1,"Availability":1,"JustificationCiaRating":"External service that receives data (like order or challenge info). Treated as a trusted integration point but could be abused if misconfigured.","Tags":["saas","webhook"],"DataAssetsProcessed":["orders"],"DataAssetsStored":[],"DataFormatsAccepted":[0],"CommunicationLinks":[],"DiagramTweakOrder":0,"RAA":1}} \ No newline at end of file diff --git a/labs/lab2/secure/data-asset-diagram.png b/labs/lab2/secure/data-asset-diagram.png new file mode 100644 index 00000000..aacf4016 Binary files /dev/null and b/labs/lab2/secure/data-asset-diagram.png differ diff --git a/labs/lab2/secure/data-flow-diagram.png b/labs/lab2/secure/data-flow-diagram.png new file mode 100644 index 00000000..5ead09e2 Binary files /dev/null and b/labs/lab2/secure/data-flow-diagram.png differ diff --git a/labs/lab2/secure/report.pdf b/labs/lab2/secure/report.pdf new file mode 100644 index 00000000..66ddc3f2 Binary files /dev/null and b/labs/lab2/secure/report.pdf differ diff --git a/labs/lab2/secure/risks.json b/labs/lab2/secure/risks.json new file mode 100644 index 00000000..0988f32e --- /dev/null +++ b/labs/lab2/secure/risks.json @@ -0,0 +1 @@ +[{"category":"missing-authentication","risk_status":"unchecked","severity":"elevated","exploitation_likelihood":"likely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Authentication\u003c/b\u003e covering communication link \u003cb\u003eTo App\u003c/b\u003e from \u003cb\u003eReverse Proxy\u003c/b\u003e to \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"missing-authentication@reverse-proxy\u003eto-app@reverse-proxy@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"reverse-proxy\u003eto-app","data_breach_probability":"possible","data_breach_technical_assets":["juice-shop"]},{"category":"unnecessary-data-transfer","risk_status":"unchecked","severity":"low","exploitation_likelihood":"unlikely","exploitation_impact":"low","title":"\u003cb\u003eUnnecessary Data Transfer\u003c/b\u003e of \u003cb\u003eTokens \u0026 Sessions\u003c/b\u003e data at \u003cb\u003eUser Browser\u003c/b\u003e from/to \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"unnecessary-data-transfer@tokens-sessions@user-browser@juice-shop","most_relevant_data_asset":"tokens-sessions","most_relevant_technical_asset":"user-browser","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["user-browser"]},{"category":"unnecessary-data-transfer","risk_status":"unchecked","severity":"low","exploitation_likelihood":"unlikely","exploitation_impact":"low","title":"\u003cb\u003eUnnecessary Data Transfer\u003c/b\u003e of \u003cb\u003eTokens \u0026 Sessions\u003c/b\u003e data at \u003cb\u003eUser Browser\u003c/b\u003e from/to \u003cb\u003eReverse Proxy\u003c/b\u003e","synthetic_id":"unnecessary-data-transfer@tokens-sessions@user-browser@reverse-proxy","most_relevant_data_asset":"tokens-sessions","most_relevant_technical_asset":"user-browser","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["user-browser"]},{"category":"missing-waf","risk_status":"unchecked","severity":"low","exploitation_likelihood":"unlikely","exploitation_impact":"low","title":"\u003cb\u003eMissing Web Application Firewall (WAF)\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"missing-waf@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["juice-shop"]},{"category":"missing-identity-store","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Identity Store\u003c/b\u003e in the threat model (referencing asset \u003cb\u003eReverse Proxy\u003c/b\u003e as an example)","synthetic_id":"missing-identity-store@reverse-proxy","most_relevant_data_asset":"","most_relevant_technical_asset":"reverse-proxy","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":[]},{"category":"missing-authentication-second-factor","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Two-Factor Authentication\u003c/b\u003e covering communication link \u003cb\u003eDirect to App (no proxy)\u003c/b\u003e from \u003cb\u003eUser Browser\u003c/b\u003e to \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"missing-authentication-second-factor@user-browser\u003edirect-to-app-no-proxy@user-browser@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"user-browser\u003edirect-to-app-no-proxy","data_breach_probability":"possible","data_breach_technical_assets":["juice-shop"]},{"category":"missing-authentication-second-factor","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Two-Factor Authentication\u003c/b\u003e covering communication link \u003cb\u003eTo App\u003c/b\u003e from \u003cb\u003eUser Browser\u003c/b\u003e forwarded via \u003cb\u003eReverse Proxy\u003c/b\u003e to \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"missing-authentication-second-factor@reverse-proxy\u003eto-app@reverse-proxy@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"reverse-proxy\u003eto-app","data_breach_probability":"possible","data_breach_technical_assets":["juice-shop"]},{"category":"container-baseimage-backdooring","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eContainer Base Image Backdooring\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"container-baseimage-backdooring@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"probable","data_breach_technical_assets":["juice-shop"]},{"category":"unnecessary-technical-asset","risk_status":"unchecked","severity":"low","exploitation_likelihood":"unlikely","exploitation_impact":"low","title":"\u003cb\u003eUnnecessary Technical Asset\u003c/b\u003e named \u003cb\u003ePersistent Storage\u003c/b\u003e","synthetic_id":"unnecessary-technical-asset@persistent-storage","most_relevant_data_asset":"","most_relevant_technical_asset":"persistent-storage","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["persistent-storage"]},{"category":"unnecessary-technical-asset","risk_status":"unchecked","severity":"low","exploitation_likelihood":"unlikely","exploitation_impact":"low","title":"\u003cb\u003eUnnecessary Technical Asset\u003c/b\u003e named \u003cb\u003eUser Browser\u003c/b\u003e","synthetic_id":"unnecessary-technical-asset@user-browser","most_relevant_data_asset":"","most_relevant_technical_asset":"user-browser","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["user-browser"]},{"category":"cross-site-request-forgery","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"very-likely","exploitation_impact":"low","title":"\u003cb\u003eCross-Site Request Forgery (CSRF)\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e via \u003cb\u003eDirect to App (no proxy)\u003c/b\u003e from \u003cb\u003eUser Browser\u003c/b\u003e","synthetic_id":"cross-site-request-forgery@juice-shop@user-browser\u003edirect-to-app-no-proxy","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"user-browser\u003edirect-to-app-no-proxy","data_breach_probability":"improbable","data_breach_technical_assets":["juice-shop"]},{"category":"cross-site-request-forgery","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"very-likely","exploitation_impact":"low","title":"\u003cb\u003eCross-Site Request Forgery (CSRF)\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e via \u003cb\u003eTo App\u003c/b\u003e from \u003cb\u003eReverse Proxy\u003c/b\u003e","synthetic_id":"cross-site-request-forgery@juice-shop@reverse-proxy\u003eto-app","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"reverse-proxy\u003eto-app","data_breach_probability":"improbable","data_breach_technical_assets":["juice-shop"]},{"category":"missing-build-infrastructure","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Build Infrastructure\u003c/b\u003e in the threat model (referencing asset \u003cb\u003eJuice Shop Application\u003c/b\u003e as an example)","synthetic_id":"missing-build-infrastructure@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":[]},{"category":"missing-vault","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eMissing Vault (Secret Storage)\u003c/b\u003e in the threat model (referencing asset \u003cb\u003eJuice Shop Application\u003c/b\u003e as an example)","synthetic_id":"missing-vault@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":[]},{"category":"unencrypted-asset","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"unlikely","exploitation_impact":"medium","title":"\u003cb\u003eUnencrypted Technical Asset\u003c/b\u003e named \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"unencrypted-asset@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["juice-shop"]},{"category":"cross-site-scripting","risk_status":"unchecked","severity":"elevated","exploitation_likelihood":"likely","exploitation_impact":"medium","title":"\u003cb\u003eCross-Site Scripting (XSS)\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"cross-site-scripting@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"possible","data_breach_technical_assets":["juice-shop"]},{"category":"server-side-request-forgery","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"likely","exploitation_impact":"low","title":"\u003cb\u003eServer-Side Request Forgery (SSRF)\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e server-side web-requesting the target \u003cb\u003eWebhook Endpoint\u003c/b\u003e via \u003cb\u003eTo Challenge WebHook\u003c/b\u003e","synthetic_id":"server-side-request-forgery@juice-shop@webhook-endpoint@juice-shop\u003eto-challenge-webhook","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"juice-shop\u003eto-challenge-webhook","data_breach_probability":"possible","data_breach_technical_assets":["juice-shop"]},{"category":"server-side-request-forgery","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"likely","exploitation_impact":"low","title":"\u003cb\u003eServer-Side Request Forgery (SSRF)\u003c/b\u003e risk at \u003cb\u003eReverse Proxy\u003c/b\u003e server-side web-requesting the target \u003cb\u003eJuice Shop Application\u003c/b\u003e via \u003cb\u003eTo App\u003c/b\u003e","synthetic_id":"server-side-request-forgery@reverse-proxy@juice-shop@reverse-proxy\u003eto-app","most_relevant_data_asset":"","most_relevant_technical_asset":"reverse-proxy","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"reverse-proxy\u003eto-app","data_breach_probability":"possible","data_breach_technical_assets":["reverse-proxy"]},{"category":"missing-hardening","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"likely","exploitation_impact":"low","title":"\u003cb\u003eMissing Hardening\u003c/b\u003e risk at \u003cb\u003eJuice Shop Application\u003c/b\u003e","synthetic_id":"missing-hardening@juice-shop","most_relevant_data_asset":"","most_relevant_technical_asset":"juice-shop","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["juice-shop"]},{"category":"missing-hardening","risk_status":"unchecked","severity":"medium","exploitation_likelihood":"likely","exploitation_impact":"low","title":"\u003cb\u003eMissing Hardening\u003c/b\u003e risk at \u003cb\u003ePersistent Storage\u003c/b\u003e","synthetic_id":"missing-hardening@persistent-storage","most_relevant_data_asset":"","most_relevant_technical_asset":"persistent-storage","most_relevant_trust_boundary":"","most_relevant_shared_runtime":"","most_relevant_communication_link":"","data_breach_probability":"improbable","data_breach_technical_assets":["persistent-storage"]}] \ No newline at end of file diff --git a/labs/lab2/secure/stats.json b/labs/lab2/secure/stats.json new file mode 100644 index 00000000..c19a18a6 --- /dev/null +++ b/labs/lab2/secure/stats.json @@ -0,0 +1 @@ +{"risks":{"critical":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":0},"elevated":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":2},"high":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":0},"low":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":5},"medium":{"accepted":0,"false-positive":0,"in-discussion":0,"in-progress":0,"mitigated":0,"unchecked":13}}} \ No newline at end of file diff --git a/labs/lab2/secure/technical-assets.json b/labs/lab2/secure/technical-assets.json new file mode 100644 index 00000000..a082acb4 --- /dev/null +++ b/labs/lab2/secure/technical-assets.json @@ -0,0 +1 @@ +{"juice-shop":{"Id":"juice-shop","Title":"Juice Shop Application","Description":"OWASP Juice Shop server (Node.js/Express, v19.0.0).","Usage":0,"Type":1,"Size":2,"Technology":6,"Machine":2,"Internet":false,"MultiTenant":false,"Redundant":false,"CustomDevelopedParts":true,"OutOfScope":false,"UsedAsClientByHuman":false,"Encryption":0,"JustificationOutOfScope":"","Owner":"Lab Owner","Confidentiality":1,"Integrity":2,"Availability":2,"JustificationCiaRating":"In-scope web application (contains all business logic and vulnerabilities by design).","Tags":["app","nodejs"],"DataAssetsProcessed":["user-accounts","orders","product-catalog","tokens-sessions"],"DataAssetsStored":["logs"],"DataFormatsAccepted":[0],"CommunicationLinks":[{"Id":"juice-shop\u003eto-challenge-webhook","SourceId":"juice-shop","TargetId":"webhook-endpoint","Title":"To Challenge WebHook","Description":"Optional outbound callback (HTTP POST) to external WebHook when a challenge is solved.","Protocol":2,"Tags":["egress"],"VPN":false,"IpFiltered":false,"Readonly":false,"Authentication":0,"Authorization":0,"Usage":0,"DataAssetsSent":["orders"],"DataAssetsReceived":null,"DiagramTweakWeight":1,"DiagramTweakConstraint":true}],"DiagramTweakOrder":0,"RAA":70.02881844380403},"persistent-storage":{"Id":"persistent-storage","Title":"Persistent Storage","Description":"Host-mounted volume for database, file uploads, and logs.","Usage":1,"Type":2,"Size":3,"Technology":10,"Machine":1,"Internet":false,"MultiTenant":false,"Redundant":false,"CustomDevelopedParts":false,"OutOfScope":false,"UsedAsClientByHuman":false,"Encryption":1,"JustificationOutOfScope":"","Owner":"Lab Owner","Confidentiality":1,"Integrity":2,"Availability":2,"JustificationCiaRating":"Local disk storage for the container – not directly exposed, but if compromised it contains sensitive data (database and logs).","Tags":["storage","volume"],"DataAssetsProcessed":[],"DataAssetsStored":["logs","user-accounts","orders","product-catalog"],"DataFormatsAccepted":[3],"CommunicationLinks":[],"DiagramTweakOrder":0,"RAA":100},"reverse-proxy":{"Id":"reverse-proxy","Title":"Reverse Proxy","Description":"Optional reverse proxy (e.g., Nginx) for TLS termination and adding security headers.","Usage":0,"Type":1,"Size":2,"Technology":20,"Machine":1,"Internet":false,"MultiTenant":false,"Redundant":false,"CustomDevelopedParts":false,"OutOfScope":false,"UsedAsClientByHuman":false,"Encryption":1,"JustificationOutOfScope":"","Owner":"Lab Owner","Confidentiality":1,"Integrity":2,"Availability":2,"JustificationCiaRating":"Not exposed to internet directly; improves security of inbound traffic.","Tags":["optional","proxy"],"DataAssetsProcessed":["product-catalog","tokens-sessions"],"DataAssetsStored":[],"DataFormatsAccepted":[0],"CommunicationLinks":[{"Id":"reverse-proxy\u003eto-app","SourceId":"reverse-proxy","TargetId":"juice-shop","Title":"To App","Description":"Proxy forwarding to app (HTTP on 3000 internally).","Protocol":2,"Tags":[],"VPN":false,"IpFiltered":false,"Readonly":false,"Authentication":0,"Authorization":0,"Usage":0,"DataAssetsSent":["tokens-sessions"],"DataAssetsReceived":["product-catalog"],"DiagramTweakWeight":1,"DiagramTweakConstraint":true}],"DiagramTweakOrder":0,"RAA":9.623538157950035},"user-browser":{"Id":"user-browser","Title":"User Browser","Description":"End-user web browser (client).","Usage":0,"Type":0,"Size":0,"Technology":2,"Machine":1,"Internet":true,"MultiTenant":false,"Redundant":false,"CustomDevelopedParts":false,"OutOfScope":false,"UsedAsClientByHuman":true,"Encryption":0,"JustificationOutOfScope":"","Owner":"External User","Confidentiality":0,"Integrity":1,"Availability":1,"JustificationCiaRating":"Client controlled by end user (potentially an attacker).","Tags":["actor","user"],"DataAssetsProcessed":[],"DataAssetsStored":[],"DataFormatsAccepted":[0],"CommunicationLinks":[{"Id":"user-browser\u003eto-reverse-proxy-preferred","SourceId":"user-browser","TargetId":"reverse-proxy","Title":"To Reverse Proxy (preferred)","Description":"User browser to reverse proxy (HTTPS on 443).","Protocol":2,"Tags":["primary"],"VPN":false,"IpFiltered":false,"Readonly":false,"Authentication":2,"Authorization":2,"Usage":0,"DataAssetsSent":["tokens-sessions"],"DataAssetsReceived":["product-catalog"],"DiagramTweakWeight":1,"DiagramTweakConstraint":true},{"Id":"user-browser\u003edirect-to-app-no-proxy","SourceId":"user-browser","TargetId":"juice-shop","Title":"Direct to App (no proxy)","Description":"Direct browser access to app (HTTP on 3000).","Protocol":2,"Tags":["direct"],"VPN":false,"IpFiltered":false,"Readonly":false,"Authentication":2,"Authorization":2,"Usage":0,"DataAssetsSent":["tokens-sessions"],"DataAssetsReceived":["product-catalog"],"DiagramTweakWeight":1,"DiagramTweakConstraint":true}],"DiagramTweakOrder":0,"RAA":25.859639506459924},"webhook-endpoint":{"Id":"webhook-endpoint","Title":"Webhook Endpoint","Description":"External WebHook service (3rd-party, if configured for integrations).","Usage":0,"Type":0,"Size":0,"Technology":14,"Machine":1,"Internet":true,"MultiTenant":true,"Redundant":true,"CustomDevelopedParts":false,"OutOfScope":true,"UsedAsClientByHuman":false,"Encryption":0,"JustificationOutOfScope":"Third-party service to receive notifications (not under our control).","Owner":"Third-Party","Confidentiality":1,"Integrity":1,"Availability":1,"JustificationCiaRating":"External service that receives data (like order or challenge info). Treated as a trusted integration point but could be abused if misconfigured.","Tags":["saas","webhook"],"DataAssetsProcessed":["orders"],"DataAssetsStored":[],"DataFormatsAccepted":[0],"CommunicationLinks":[],"DiagramTweakOrder":0,"RAA":1}} \ No newline at end of file diff --git a/labs/lab2/threagile-model.secure.yaml b/labs/lab2/threagile-model.secure.yaml new file mode 100644 index 00000000..4bfdf2fd --- /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-02-16 + +author: + name: Daniel Gevorgyan + 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)." + 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: transparent + 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/lab2/threagile-model.yaml b/labs/lab2/threagile-model.yaml index 85c01a79..a6092993 100644 --- a/labs/lab2/threagile-model.yaml +++ b/labs/lab2/threagile-model.yaml @@ -1,10 +1,10 @@ threagile_version: 1.0.0 title: OWASP Juice Shop — Local Lab Threat Model -date: 2025-09-18 +date: 2025-02-16 author: - name: Student Name + name: Daniel Gevorgyan homepage: https://example.edu management_summary_comment: > diff --git a/labs/submission1.md b/labs/submission1.md new file mode 100644 index 00000000..dbb1ccc3 --- /dev/null +++ b/labs/submission1.md @@ -0,0 +1,41 @@ +# Triage Report — OWASP Juice Shop + +## Scope & Asset +- Asset: OWASP Juice Shop (local lab instance) +- Image: bkimminich/juice-shop:v19.0.0 +- Release link/date: +- Image digest (optional): + +## Environment +- Host OS: NixOS 26.05 (Yarara) x86_64 +- Docker: 29.1.5 + +## Deployment Details +- Run command used: `docker run -d --name juice-shop -p 127.0.0.1:3000:3000 bkimminich/juice-shop:v19.0.0` +- Access URL: http://127.0.0.1:3000 +- Network exposure: 127.0.0.1 only [x] Yes [ ] No + +## Health Check +- Page load: ![Page load](./submission1/page-load.png) +- API check: first 5–10 lines from `curl -s http://127.0.0.1:3000/rest/products | head` + +## Surface Snapshot (Triage) +- Login/Registration visible: [x] Yes [ ] No — notes: Login is visible under Account button on a page header +- Product listing/search present: [x] Yes [ ] No — notes: Products are displayed +- Admin or account area discoverable: [x] Yes [ ] No +- Client-side errors in console: [ ] Yes [x] No — notes: no errors are leaked +- Security headers (quick look — optional): `curl -I http://127.0.0.1:3000` → CSP/HSTS present? notes: Basic security headers present but missing CSP and HSTS headers + +## Risks Observed (Top 3) +1) Missing Content Security Policy (CSP) -- + Application lacks CSP headers, making it vulnerable to XSS attacks as there are no restrictions on script sources or inline execution. +2) No HTTP Strict Transport Security (HSTS) -- + Absence of HSTS headers leaves the application susceptible to SSL stripping attacks and protocol downgrades. +3) Exposed Admin Interface -- + Administrative endpoints are discoverable without proper rate limiting or multi-factor authentication, potentially allowing brute force attacks. + + +## GitHub Community + +Starring repositories helps signal project quality and usefulness, supports maintainers through visible appreciation, and improves discoverability of valuable open-source tools. Following developers makes it easier to track relevant work, learn from others’ approaches, and build professional connections that support effective collaboration and long-term career growth. + diff --git a/labs/submission1/page-load.png b/labs/submission1/page-load.png new file mode 100644 index 00000000..af73e664 Binary files /dev/null and b/labs/submission1/page-load.png differ diff --git a/labs/submission2.md b/labs/submission2.md new file mode 100644 index 00000000..40510b3a --- /dev/null +++ b/labs/submission2.md @@ -0,0 +1,136 @@ +# Lab 2 — Threat Modeling with Threagile + +## Overview + +This submission documents the threat modeling of the OWASP Juice Shop (`bkimminich/juice-shop:v19.0.0`) using Threagile. +The lab includes a baseline threat model, a secure HTTPS variant, and a comparative risk analysis demonstrating how security controls affect the risk landscape. + +--- + +## Task 1 — Threagile Baseline Model + +### Baseline Model Generation + +- Threagile was executed using the provided YAML model: + - Model file: `lab2/threagile-model.yaml` + - Output directory: `lab2/baseline/` +- The Docker-based Threagile run successfully generated: + - `report.pdf` + - Risk data (`risks.json`, `stats.json`, `technical-assets.json`) + - Data-flow and asset diagrams (PNG) + +### Generated Artifacts + +- PDF Report: `lab2/baseline/report.pdf` +- Diagrams: + - Data Flow Diagram: `lab2/baseline/data-flow-diagram.png` + - Data Asset Diagram: `lab2/baseline/data-asset-diagram.png` +- Risk Export: `lab2/baseline/risks.json` + +--- + +### Risk Ranking Methodology + +Risks were ranked using a composite score calculated as follows: + +``` +Composite Score = Severity × 100 + Likelihood × 10 + Impact +``` + +**Scoring values used:** + +| Dimension | Values | +|-----------|--------| +| Severity | critical (5), elevated (4), high (3), medium (2), low (1) | +| Likelihood| very-likely (4), likely (3), possible (2), unlikely (1) | +| Impact | high (3), medium (2), low (1) | + +The Top 5 risks were selected based on the highest composite scores. + +--- + +### Top 5 Risks (Baseline) + +| Rank | Risk Title | Category | Asset | Severity | Likelihood | Impact | Composite Score | +|-----:|------------------------------------|-----------------------------|-------------|--------------|-------------|----------|-----------------| +| 1 | Unencrypted Communicatin | unencrypted-communication | Application | elevated (4) | likely (3) | high (3) | 433 | +| 2 | Missing Authentication | missing-authentication | Application | elevated (4) | likely (3) | high (3) | 432 | +| 3 | Cross-Site Scripting (XSS) | cross-site-scripting | Application | elevated (4) | likely (3) | high (3) | 432 | +| 4 | Cross-Site Request Forgery (CSRF) | cross-site-request-forgery | Application | high (3) | likely (3) | high (3) | 241 | +| 5 | Server-Side Request Forgery (SSRF) | server-side-request-forgery | Application | high (3) | possible (2)| high (3) | 231 | + +--- + +### Baseline Risk Analysis + +The baseline threat model highlights several critical application-layer risks. Unencrypted communication represents the highest risk due to the potential for credential leakage and data interception. Authentication-related weaknesses and common web vulnerabilities such as XSS and CSRF further increase the attack surface, particularly in a deliberately vulnerable application like OWASP Juice Shop. SSRF remains a concern due to its potential to access internal resources. + +--- + +## Task 2 — Secure HTTPS Variant & Risk Comparison + +### Secure Model Changes + +A secure variant of the baseline model was created at: `lab2/threagile-model.secure.yaml` + +The following changes were applied: + +- Communication between **User Browser → Application** set to `protocol: https` +- Communication involving the **Reverse Proxy** set to `protocol: https` +- **Persistent Storage** configured with `encryption: transparent` + +No asset names or architectural structure were changed to ensure accurate risk comparison. + +--- + +### Secure Variant Generation + +- Output directory: `lab2/secure/` +- Generated artifacts: + - `report.pdf` + - Updated diagrams + - Updated `risks.json` + +--- + +### Risk Category Delta Table + +The following table compares the number of risks per category between the baseline and secure models: + +| Category | Baseline | Secure | Δ | +|---|---:|---:|---:| +| container-baseimage-backdooring | 1 | 1 | 0 | +| cross-site-request-forgery | 2 | 2 | 0 | +| cross-site-scripting | 1 | 1 | 0 | +| missing-authentication | 1 | 1 | 0 | +| missing-authentication-second-factor | 2 | 2 | 0 | +| missing-build-infrastructure | 1 | 1 | 0 | +| missing-hardening | 2 | 2 | 0 | +| missing-identity-store | 1 | 1 | 0 | +| missing-vault | 1 | 1 | 0 | +| missing-waf | 1 | 1 | 0 | +| server-side-request-forgery | 2 | 2 | 0 | +| unencrypted-asset | 2 | 1 | -1 | +| unencrypted-communication | 2 | 0 | -2 | +| unnecessary-data-transfer | 2 | 2 | 0 | +| unnecessary-technical-asset | 2 | 2 | 0 | + +--- + +### Delta Analysis + +The baseline threat model highlights several critical application-layer risks. Unencrypted communication represents the highest risk due to the potential for credential leakage and data interception. Authentication-related weaknesses and common web vulnerabilities such as XSS and CSRF further increase the attack surface, particularly in a deliberately vulnerable application like OWASP Juice Shop. SSRF remains a concern due to its potential to access internal resources. + +--- + +### Diagram Comparison +- Baseline Diagrams: `lab2/baseline/data-flow-diagram.png`, `lab2/baseline/data-asset-diagram.png` +- Secure Diagram: `lab2/secure/data-flow-diagram.png`, `lab2/baseline/data-asset-diagram.png` + +The data-flow diagram reflects the transition to HTTPS, while the data-asset diagram remains unchanged, as encryption at rest does not alter asset relationships. + +--- + +## Conclusion + +This lab demonstrates how threat modeling as code enables systematic evaluation of security controls. Introducing HTTPS and encryption at rest significantly reduced transport and storage-related risks while leaving application-layer vulnerabilities unchanged. This highlights the importance of layered defenses and complementary controls when securing web applications. diff --git a/labs/submission3.md b/labs/submission3.md new file mode 100644 index 00000000..c65ede40 --- /dev/null +++ b/labs/submission3.md @@ -0,0 +1,96 @@ +# Lab 3 — Secure Git Submission + +## Task 1 — SSH Commit Signature Verification + +### Summary of Commit Signing Benefits +Commit signing is like a digital fingerprint for your code. When you sign a commit with an SSH key, you're cryptographically proving that you—and only you—created that commit. The key benefits include: +- Authentication: Verifies that the commit actually came from you, not someone impersonating you +- Integrity: Guarantees the code hasn't been tampered with after you wrote it +- Trust: GitHub shows a nice green "Verified" badge +- Accountability: Creates a clear audit trail of who did what +- Professionalism: Shows you follow security best practices + +### SSH Key Setup and Configuration + +#### Step 1: Generate SSH Key + +```bash +$ ssh-keygen -t ed25519 -C "your_email@example.com" +Generating public/private ed25519 key pair. +Enter file in which to save the key (/home/daniel/.ssh/id_ed25519): +Enter passphrase (empty for no passphrase): +Enter same passphrase again: +Your identification has been saved in /home/daniel/.ssh/id_ed25519 +Your public key has been saved in /home/daniel/.ssh/id_ed25519.pub +``` + +#### Step 2: Add Public Key to GitHub +- Copied the public key: cat ~/.ssh/id_ed25519.pub +- Added to GitHub: Settings → SSH and GPG keys → New SSH Key + +#### Step 3: Configure Git for SSH Signing + +```bash +$ git config --global user.signingkey ~/.ssh/id_ed25519 +$ git config --global commit.gpgSign true +$ git config --global gpg.format ssh + +$ git config --global --list | grep -E "(gpg|signing)" +commit.gpgsign=true +gpg.format=ssh +user.signingkey=~/.ssh/id_ed25519 +``` + +### Signed Commit Creation + +#### Verified Badge Evidence: + +![Verified commit screenshot](./submission3/verified-commit.png) + +After pushing to GitHub, my commit shows a green "Verified" badge, confirming: +- The SSH key on GitHub matches the one used to sign +- The commit content hasn't been altered +- The signature is cryptographically valid + +### Analysis: Why is Commit Signing Critical in DevSecOps? + +Commit signing is a fundamental security control in modern DevSecOps for several reasons: + +1. Supply Chain Security +Attackers often target the development pipeline itself. Signed commits ensure that code entering your CI/CD pipeline hasn't been tampered with. If a commit isn't signed or the signature doesn't verify, you know something's wrong before it ever reaches production. + +2. Trust in Automation +CI/CD systems can automatically verify signatures before building and deploying. This enables policies like "only deploy code signed by authorized developers." Without signatures, automation has no way to distinguish between legitimate code and malicious injections. + +3. Audit and Compliance +In regulated industries, you need to prove who did what and when. Signed commits provide cryptographic proof that meets compliance requirements like SOC2, PCI-DSS, and FedRAMP. + +4. Incident Response +When things go wrong, verified signatures help investigators distinguish between legitimate developer activity and potential attacks. If a commit isn't signed or verification fails, it's immediately suspect. + +5. Zero Trust Architecture +"Never trust, always verify" applies to code too. Every commit should be verified before integration. With commit signing, you're treating every commit as potentially malicious until proven otherwise. + +Without commit signing, anyone with push access could impersonate another developer, inject malicious code, and there would be no way to prove tampering occurred. In DevSecOps, where security is built into every step, commit signing is the foundation of code integrity. + + +## Task 2 – Pre‑commit Secret Scanning + +### Hook Setup +- Hook file created at `.git/hooks/pre-commit` with the provided script. +- Made executable with `chmod +x`. +- Docker is required and was available. + +### Testing Results + +#### 1. Blocked commit (secret detected) +- Added `test.txt` containing fake github token +- Ran `git add test.txt` and `git commit -m "test secret"`. +![Failed commit screenshot](./submission3/failed-commit.png) + +### Analysis of Automated Secret Scanning +- Pre‑commit hooks run **before** a commit is created, so secrets never enter the local Git history. +- Tools like TruffleHog and Gitleaks use regex patterns and entropy analysis to detect credentials, API keys, and other sensitive strings. +- By integrating these tools into the development workflow, teams can catch accidental exposures early, reducing the risk of credentials being pushed to remote repositories. +- The hook also demonstrates how to **allow** certain directories (like `lectures/`) for educational purposes while still scanning the rest of the codebase. + diff --git a/labs/submission3/failed-commit.png b/labs/submission3/failed-commit.png new file mode 100644 index 00000000..dabcab72 Binary files /dev/null and b/labs/submission3/failed-commit.png differ diff --git a/labs/submission3/verified-commit.png b/labs/submission3/verified-commit.png new file mode 100644 index 00000000..15dda89a Binary files /dev/null and b/labs/submission3/verified-commit.png differ