Threat Modeling & Đánh giá rủi roThreat Modeling & Risk Assessment
Thuộc bộ kiến thức DevSecOps Roadmap.
Tổng quan
Threat modeling là hoạt động “suy nghĩ như một kẻ tấn công” trước khi kẻ tấn công thật sự làm điều đó — xác định một cách có hệ thống điều gì có thể sai (what can go wrong), mức độ nghiêm trọng của nó, và cần làm gì để xử lý. Đây là một trong những hoạt động bảo mật có đòn bẩy (leverage) cao nhất trong SDLC vì nó diễn ra trên giấy (hoặc bảng trắng, hoặc công cụ vẽ diagram) — trước khi một dòng code nào được viết hay một đồng nào bị tiêu tốn để xây “đúng nhưng sai kiến trúc”.
Đánh giá rủi ro (risk assessment) là kỷ luật đi kèm: biến danh sách threat thành các quyết định ưu tiên, có thể hành động — rủi ro nào cần fix ngay, rủi ro nào chấp nhận (accept), rủi ro nào chuyển giao (transfer — bảo hiểm, hợp đồng), và rủi ro nào chỉ cần theo dõi.
Tại sao làm sớm (shift-left)
- Chi phí bất đối xứng: một lỗi thiết kế (design flaw) phát hiện trong buổi threat-modeling chỉ tốn một cuộc thảo luận; cùng lỗi đó phát hiện ở production tốn một sự cố (incident), một postmortem, mất niềm tin khách hàng, và có thể phải công bố vi phạm dữ liệu (breach disclosure).
- Kiến trúc khó vá: bạn có thể patch một buffer overflow bằng một bản fix code; nhưng thường không thể “patch” việc “service tin tưởng một header không xác thực” mà không thiết kế lại. Threat modeling nhắm đúng vào lớp lỗi mà code review và scanner hay bỏ sót — lỗi logic và lỗi trust boundary.
- Hiểu biết chung: bản thân bài tập buộc developer, architect và security engineer phải thống nhất hệ thống thực sự làm gì — điều này thường lộ ra các bug và requirement thiếu sót không liên quan đến bảo mật.
- Liên tục, không phải một lần: threat modeling hiện đại được lồng vào design review, PR template, và sprint planning — không phải một workshop duy nhất trước khi ra mắt rồi không bao giờ xem lại.
Bốn câu hỏi
Framework của Adam Shostack (được dùng trong Microsoft SDL và áp dụng rộng rãi) rút gọn threat modeling về bốn câu hỏi, lý tưởng nhất là hỏi lặp lại như một vòng lặp:
| # | Câu hỏi | Hoạt động |
|---|---|---|
| 1 | Chúng ta đang xây dựng cái gì? | Vẽ kiến trúc / data flow diagram (DFD), xác định component, trust boundary, data store, external entity. |
| 2 | Điều gì có thể sai (what can go wrong)? | Áp dụng một framework (STRIDE, attacker persona, kill chain) để liệt kê threat theo từng component/boundary. |
| 3 | Chúng ta sẽ làm gì với nó? | Quyết định mitigation: fix ở thiết kế, fix ở code, thêm control, chấp nhận rủi ro (accept), hoặc chuyển giao (transfer). |
| 4 | Chúng ta đã làm tốt chưa? | Retrospective — kiểm tra lại threat model so với thực tế, xác nhận mitigation đã thực sự triển khai, chạy lại khi hệ thống thay đổi. |
Câu hỏi số 4 là câu hay bị bỏ qua nhất nhưng lại quan trọng nhất để biến threat modeling thành một quy trình sống thay vì một ô checkbox tuân thủ.
Kiến thức nền tảng
Từ vựng cốt lõi
| Thuật ngữ | Định nghĩa |
|---|---|
| Asset | Bất cứ thứ gì có giá trị cần bảo vệ: dữ liệu, credential, tính khả dụng (availability), uy tín, sở hữu trí tuệ. |
| Threat | Một sự kiện hoặc hành động tiềm ẩn của attacker có thể gây hại cho asset (ví dụ: “kẻ tấn công giả mạo JWT để mạo danh một user”). |
| Vulnerability | Điểm yếu mà một threat có thể khai thác (ví dụ: thiếu xác minh chữ ký trên JWT). |
| Attack vector / entry point | Đường mà attacker dùng để tương tác với hệ thống (API endpoint, form upload, cổng mạng). |
| Attack surface | Toàn bộ tập hợp entry point và vector mà attacker có thể dùng — càng nhỏ càng ít thứ phải phòng thủ. |
| Trust boundary | Điểm trong hệ thống nơi dữ liệu hoặc quyền kiểm soát đi qua giữa các component có mức độ tin cậy khác nhau (ví dụ: internet → API gateway, user → admin). |
| Risk | Sự kết hợp giữa likelihood (khả năng xảy ra) và impact (tác động) của một threat khi nó thành hiện thực — thứ bạn thực sự ưu tiên và hành động. |
| Mitigation / control | Biện pháp bảo vệ làm giảm likelihood hoặc impact (authentication, input validation, rate limiting, encryption). |
| Residual risk | Phần rủi ro còn lại sau khi áp dụng mitigation — không bao giờ bằng 0, phải được ai đó có trách nhiệm chấp nhận rõ ràng. |
Attack surface mapping
Trước khi hỏi “điều gì có thể sai”, bạn cần một bức tranh chính xác về hệ thống. Attack surface mapping nghĩa là liệt kê:
- Entry point: mọi nơi input từ bên ngoài đi vào hệ thống — public API, webhook, file upload, consumer của message queue, admin panel, CLI tool, tích hợp bên thứ ba, kể cả DNS và TLS termination.
- Trust boundary: mọi điểm giao cắt nơi mức độ tin cậy thay đổi — internet → DMZ, DMZ → mạng nội bộ, user role → admin role, service A → service B (đặc biệt giữa các team hoặc vendor khác nhau), container → host.
- Data flow: dữ liệu di chuyển như thế nào và được lưu, biến đổi, hoặc log ở đâu — đây thường là nơi ẩn giấu các vấn đề information disclosure.
- Dependency: thư viện bên thứ ba, tích hợp SaaS, pipeline CI/CD, và nhà cung cấp hạ tầng — mỗi thứ là một entry point tiềm ẩn cho supply-chain attack (xem Bảo mật CI/CD & Supply Chain).
Data Flow Diagram (DFD) là ký hiệu chuẩn cho việc này. Một DFD có bốn loại phần tử:
| Ký hiệu | Phần tử | Ý nghĩa |
|---|---|---|
| Hình tròn / chữ nhật bo góc | Process | Component biến đổi dữ liệu (một service, một function, một microservice). |
| Hình chữ nhật | External entity | Thứ nằm ngoài tầm kiểm soát của bạn tương tác với hệ thống (một user, một API bên thứ ba). |
| Hai đường thẳng song song | Data store | Nơi dữ liệu được lưu trữ (database, cache, file system, queue). |
| Mũi tên | Data flow | Sự di chuyển dữ liệu giữa các phần tử. |
| Đường nét đứt | Trust boundary | Điểm giao cắt nơi mức độ quyền/tin cậy thay đổi. |
Kỷ luật vẽ DFD — dù chỉ là phác thảo không chính thức — thường là nơi mang lại giá trị thực sự của threat modeling: team phát hiện các component họ quên mất là tồn tại, các data flow không ai từng document, và trust boundary không ai từng đồng ý là boundary.
Khái niệm chính
STRIDE
STRIDE là mnemonic của Microsoft cho sáu loại threat, mỗi loại ánh xạ tới một thuộc tính bảo mật bị vi phạm. Áp dụng nó cho từng phần tử của DFD (mỗi process, data store, data flow, và external entity), và hỏi “điều này có thể xảy ra ở đây không?”
| Loại | Vi phạm | Định nghĩa | Ví dụ |
|---|---|---|---|
| S — Spoofing | Authentication | Giả mạo là một thứ/người khác không phải mình. | Attacker giả mạo session cookie để đăng nhập như một user khác; một service mạo danh một microservice khác bằng API key bị đánh cắp. |
| T — Tampering | Integrity | Sửa đổi dữ liệu hoặc code mà không có quyền. | Sửa tham số giá trong một request client-side không ký trước khi nó đến checkout API; thay đổi payload của JWT khi chữ ký không được xác minh. |
| R — Repudiation | Non-repudiation | Chối bỏ đã thực hiện một hành động, không có cách nào chứng minh ngược lại. | Một user xóa dữ liệu của user khác và hệ thống không có audit log gắn hành động với một identity. |
| I — Information Disclosure | Confidentiality | Để lộ thông tin cho người không có quyền xem. | API trả về toàn bộ user object (bao gồm password hash hoặc internal ID) trong khi chỉ cần display name; thông báo lỗi quá chi tiết lộ stack trace. |
| D — Denial of Service | Availability | Làm giảm hoặc từ chối dịch vụ với người dùng hợp lệ. | Một endpoint không xác thực chấp nhận upload file lớn không giới hạn kích thước, làm cạn kiệt dung lượng đĩa; một regex dễ bị ReDoS trên input người dùng. |
| E — Elevation of Privilege | Authorization | Đạt được năng lực mà không có quyền phù hợp. | Một user thường gọi trực tiếp API endpoint chỉ dành cho admin vì frontend ẩn nút bấm nhưng backend không kiểm tra role. |
Cách chạy một buổi STRIDE trong thực tế:
- Vẽ hoặc import DFD.
- Với mỗi phần tử (process, data store, data flow, external entity), đi qua cả sáu chữ cái và hỏi “threat này có áp dụng ở đây không, và áp dụng như thế nào?”
- Không phải chữ cái nào cũng áp dụng cho mọi phần tử — ví dụ, một data store thuần túy khi ở trạng thái nghỉ (at rest) hiếm khi là mục tiêu Spoofing, nhưng rất có thể là mục tiêu Tampering và Information Disclosure.
- Ghi lại mỗi threat được xác định với: component, loại STRIDE, mô tả, và mức độ nghiêm trọng sơ bộ.
- Chuyển sang lập kế hoạch mitigation (xem phần “Chuyển threat thành backlog item” bên dưới).
Một quy tắc tắt phổ biến về mức độ liên quan STRIDE theo loại phần tử:
| Loại phần tử | Mức độ liên quan STRIDE điển hình |
|---|---|
| External entity | S, R (không thể tamper với thứ bạn không sở hữu, không thể DoS một con người, nhưng có thể spoof identity và repudiate hành động) |
| Process | S, T, R, I, D, E (cả sáu đều áp dụng) |
| Data store | T, I, D, R (nếu thiếu lịch sử thay đổi) |
| Data flow | T, I, D |
PASTA (Process for Attack Simulation and Threat Analysis)
PASTA là một phương pháp risk-centric, được dẫn dắt bởi góc nhìn attacker (khác với STRIDE vốn design-centric, dẫn dắt bởi developer). Nó nặng hơn và thường dùng cho ứng dụng giá trị cao, đánh giá rủi ro chính thức, hoặc khi threat modeling cần gắn trực tiếp với impact kinh doanh và báo cáo compliance. Nó có bảy giai đoạn:
| Giai đoạn | Tên | Mục tiêu |
|---|---|---|
| 1 | Định nghĩa mục tiêu | Xác định mục tiêu kinh doanh, yêu cầu compliance, và các asset quan trọng. |
| 2 | Định nghĩa phạm vi kỹ thuật | Liệt kê môi trường kỹ thuật: hạ tầng, dependency ứng dụng, thành phần phần mềm. |
| 3 | Phân rã ứng dụng (application decomposition) | Xây dựng DFD, xác định entry point, trust boundary và asset (nền tảng tương tự bước 1 của STRIDE). |
| 4 | Phân tích threat | Phân tích threat intelligence, động cơ attacker, và các mẫu tấn công đã biết liên quan đến bối cảnh kinh doanh. |
| 5 | Phân tích vulnerability & weakness | Đối chiếu threat đã xác định với vulnerability thực tế (kết quả scan, phát hiện từ code review, CVE). |
| 6 | Mô hình hóa / mô phỏng tấn công | Mô hình hóa attack tree/attack chain thực tế cho thấy threat và vulnerability kết hợp thành đường tấn công khả thi ra sao. |
| 7 | Phân tích rủi ro & impact | Định lượng rủi ro kinh doanh, gán residual risk, đề xuất biện pháp đối phó theo ưu tiên impact. |
Giá trị của PASTA là nó gắn threat kỹ thuật với impact kinh doanh một cách rõ ràng ở mọi giai đoạn, giúp dễ dàng thuyết phục đầu tư với các bên liên quan không kỹ thuật. Cái giá phải trả là nó đòi hỏi nhiều thời gian, threat intelligence và sự tham gia liên chức năng hơn hẳn STRIDE.
STRIDE vs PASTA
| Khía cạnh | STRIDE | PASTA |
|---|---|---|
| Approach | Design-centric, do developer dẫn dắt | Risk-centric, do attacker/business dẫn dắt |
| Trọng tâm | ”Điều gì có thể sai trong thiết kế này” theo từng component | ”Kẻ tấn công thật sự sẽ làm gì, và impact kinh doanh là gì” |
| Xuất xứ | Microsoft SDL | VerSprite (2012, Tony UcedaVélez & Marco Morana) |
| Mức độ nỗ lực | Nhẹ, nhanh, lặp lại | Nặng, chính thức, nhiều giai đoạn |
| Phù hợp nhất cho | Threat modeling theo feature/sprint, workflow dev hằng ngày | Ứng dụng giá trị cao, đánh giá theo quy định/compliance, báo cáo rủi ro cấp điều hành |
| Kết quả | Danh sách threat theo từng phần tử DFD kèm mitigation | Mô phỏng tấn công, rủi ro kinh doanh được lượng hóa, roadmap biện pháp đối phó theo ưu tiên |
| Ai tham gia | Developer, architect, security champion | Security team, risk/compliance, business stakeholder, threat intel |
| Khi nào dùng | Mỗi feature mới, API mới, hoặc thay đổi thiết kế đáng kể | Đánh giá rủi ro hàng năm/theo major release, hệ thống rủi ro cao mới, audit |
Các framework khác đáng biết (ngắn gọn): DREAD (Damage, Reproducibility, Exploitability, Affected users, Discoverability — một mô hình chấm điểm, thường đi kèm STRIDE, dù Microsoft đã ngừng dùng nội bộ vì bị đánh giá quá chủ quan), Attack Trees (phân rã dạng cây cho thấy một mục tiêu có thể đạt được bằng cách nào), LINDDUN (tương đương STRIDE nhưng tập trung vào privacy: Linkability, Identifiability, Non-repudiation, Detectability, Disclosure of information, Unawareness, Non-compliance), và ma trận MITRE ATT&CK (một cơ sở tri thức về tactic/technique của attacker thực tế, hữu ích để đưa kịch bản threat dựa trên hành vi đã quan sát thay vì lý thuyết).
Threat modeling trong SDLC
| Giai đoạn | Hoạt động |
|---|---|
| Design / RFC | Threat model đầy đủ cho service mới hoặc thay đổi kiến trúc lớn: DFD + STRIDE, được security review. |
| Sprint planning / theo feature | Threat model “mini” nhẹ nhàng cho endpoint mới, data flow mới, tích hợp bên thứ ba mới — 15–30 phút, không phải workshop đầy đủ. |
| PR / code review | Checklist threat modeling nhúng trong PR template cho các thay đổi nhạy cảm về bảo mật (auth, thanh toán, xử lý PII). |
| Trước khi release | Xác thực lại model so với những gì thực sự được xây dựng; xác nhận mitigation đã triển khai (câu hỏi 4: “chúng ta đã làm tốt chưa?”). |
| Sau incident | Cập nhật threat model với đường tấn công mới được phát hiện — incident chính là threat mà bạn đã bỏ sót. |
| Xem lại định kỳ | Xem lại model cho hệ thống hiện có theo chu kỳ (ví dụ hàng năm, hoặc khi dependency/kiến trúc thay đổi lớn) vì attack surface thay đổi khi code thay đổi. |
Ai tham gia:
- Developer / tech lead — chịu trách nhiệm về độ chính xác của DFD và triển khai mitigation.
- Security champion / kỹ sư AppSec — điều phối buổi làm việc, mang đến góc nhìn STRIDE/attacker, review độ bao phủ.
- Architect — đảm bảo trust boundary và data flow phản ánh đúng thiết kế thực tế.
- Product/business stakeholder — cần thiết cho chấm điểm impact kinh doanh kiểu PASTA, ít cần thiết hơn cho buổi STRIDE nhẹ nhàng.
Giữ cho nó nhẹ nhàng và liên tục (chế độ thất bại lớn nhất trong thực tế là coi threat modeling là một workshop nặng nề duy nhất rồi không bao giờ xem lại):
- Dùng template/checklist để một buổi chỉ mất 30–60 phút, không phải nhiều ngày.
- Threat-model phần thay đổi (delta), không phải toàn bộ hệ thống, cho các thay đổi nhỏ — chỉ vẽ lại DFD đầy đủ khi kiến trúc thực sự thay đổi.
- Lưu model dưới dạng code/markdown cạnh design doc hoặc repo, có version control, để nó tiến hóa cùng hệ thống.
- Tự động hóa nơi có thể: các công cụ threat modeling (OWASP Threat Dragon, Microsoft Threat Modeling Tool, IriusRisk, pytm) có thể tái tạo diagram và danh sách threat từ một định nghĩa model có thể script hóa, khiến việc chạy lại rẻ hơn nhiều.
- Gắn threat đã xác định trực tiếp vào backlog (xem bên dưới) để mitigation không chỉ là một tài liệu bị quên lãng.
Định lượng rủi ro (Risk quantification)
Một khi threat đã được liệt kê, bạn cần ưu tiên — không thể fix mọi thứ cùng lúc, và một số phát hiện không đáng để fix so với chi phí bỏ ra.
Likelihood × Impact là công thức nền tảng cho cả cách tiếp cận qualitative lẫn quantitative:
Risk = Likelihood × Impact
Ma trận rủi ro định tính (qualitative risk matrix) (nhanh, phổ biến trong các buổi kiểu STRIDE):
| Impact ↓ / Likelihood → | Thấp | Trung bình | Cao |
|---|---|---|---|
| Cao | Trung bình | Cao | Nghiêm trọng (Critical) |
| Trung bình | Thấp | Trung bình | Cao |
| Thấp | Thấp | Thấp | Trung bình |
- Yếu tố Likelihood: kỹ năng attacker cần có, control hiện có, mức độ tiếp xúc (internet-facing hay internal), liệu đã từng bị khai thác ở nơi khác chưa.
- Yếu tố Impact: mất mát confidentiality/integrity/availability, chi phí tài chính, rủi ro pháp lý/quy định, thiệt hại uy tín, phạm vi ảnh hưởng (blast radius — một user hay tất cả tenant).
Cách tiếp cận định lượng (quantitative) gán giá trị tiền tệ/số liệu, hữu ích khi cần thuyết phục đầu tư với finance/ban điều hành:
- ALE (Annualized Loss Expectancy) = SLE (Single Loss Expectancy) × ARO (Annualized Rate of Occurrence).
- Ví dụ: một vụ rò rỉ dữ liệu ước tính tốn 2 triệu USD (SLE) với khả năng xảy ra hàng năm ước tính 5% (ARO) → ALE = 100.000 USD/năm. Con số này cho một mức trần hợp lý về việc nên chi bao nhiêu mỗi năm để giảm thiểu rủi ro đó.
- CVSS (Common Vulnerability Scoring System) — chuẩn chấm điểm cho vulnerability đã biết (0–10), hữu ích để ưu tiên phát hiện từ scanner/pentest nhưng ít phù hợp với threat mới ở mức thiết kế vì nó được xây dựng xoay quanh vulnerability kiểu CVE đã biết.
- FAIR (Factor Analysis of Information Risk) — mô hình định lượng chặt chẽ hơn, phân rã rủi ro thành tần suất sự kiện tổn thất và mức độ tổn thất với phân phối xác suất, phổ biến trong các chương trình quản lý rủi ro trưởng thành (xem Compliance, Governance & Quản lý rủi ro).
Các lựa chọn xử lý rủi ro (risk treatment) — một khi rủi ro đã được chấm điểm, cần quyết định:
| Lựa chọn | Ý nghĩa |
|---|---|
| Mitigate (giảm thiểu) | Giảm likelihood hoặc impact bằng một control (mặc định cho mọi thứ vượt ngưỡng chấp nhận rủi ro của bạn). |
| Accept (chấp nhận) | Chính thức ghi nhận và ký duyệt residual risk (phải có chủ sở hữu được đặt tên, chịu trách nhiệm — không phải im lặng). |
| Transfer (chuyển giao) | Chuyển impact tài chính sang nơi khác (bảo hiểm mạng, điều khoản bồi thường hợp đồng với vendor). |
| Avoid (tránh) | Loại bỏ rủi ro bằng cách gỡ bỏ hoàn toàn feature/component/dependency. |
Risk register: artifact theo dõi tất cả những điều trên theo thời gian — thường là một bảng/spreadsheet hoặc một trường trong công cụ GRC với các cột như: ID, mô tả, asset, loại threat, likelihood, impact, điểm rủi ro, quyết định xử lý, chủ sở hữu, trạng thái, ngày đến hạn, ngày review gần nhất. Đây là hồ sơ sống mà auditor và lãnh đạo thực sự nhìn vào; một threat model không bao giờ được đưa vào risk register thường bị quên lãng.
OWASP Top 10 như một checklist threat modeling
OWASP Top 10 không thay thế cho threat modeling, nhưng là một checklist tuyệt vời để kiểm tra độ bao phủ (sanity-check) sau khi bạn đã liệt kê threat qua STRIDE/PASTA — đặc biệt với ứng dụng web, vì nó nắm bắt các lớp vulnerability bị khai thác phổ biến nhất trong thực tế:
- Broken Access Control, Cryptographic Failures, Injection, Insecure Design, Security Misconfiguration, Vulnerable & Outdated Components, Identification & Authentication Failures, Software & Data Integrity Failures, Security Logging & Monitoring Failures, Server-Side Request Forgery (SSRF).
Đối chiếu chéo: với mỗi threat STRIDE đã xác định, hỏi “threat này có ánh xạ tới một hạng mục OWASP Top 10 không, và nếu có, đã có mitigation chuẩn nào được biết đến chưa?” Việc bao phủ sâu ở mức code cho các hạng mục này (kèm mẫu secure-coding cụ thể) được trình bày trong Secure Coding & Bảo mật ứng dụng Web — note này chỉ dừng ở mức thiết kế/xác định threat.
Chuyển threat thành backlog item / yêu cầu bảo mật
Một threat model chỉ nằm trong tài liệu gần như vô giá trị. Mỗi threat được xác định nên trở thành một trong các dạng sau:
- Một yêu cầu bảo mật (security requirement) được viết trước/trong khi thiết kế (ví dụ: “mọi endpoint admin phải xác minh role ở server-side, không bao giờ tin tưởng việc ẩn UI ở client-side”).
- Một ticket backlog với mức độ nghiêm túc tương đương một bug chức năng: kịch bản tái hiện, mức độ nghiêm trọng, component bị ảnh hưởng, đề xuất fix, tiêu chí chấp nhận.
- Một bản ghi chấp nhận rủi ro rõ ràng trong risk register, có chủ sở hữu được đặt tên và ngày review, nếu chưa fix ngay.
- Một test case — lý tưởng là tự động (một unit/integration test bảo mật, một rule DAST, một policy-as-code check) để regression được phát hiện tự động về sau.
Một template ánh xạ đơn giản:
| Threat ID | Loại STRIDE | Component | Mô tả | Likelihood | Impact | Risk | Mitigation | Ticket backlog | Owner | Trạng thái |
|---|
Ví dụ thực hành: Feature “Đăng nhập + Upload File”
Mô tả hệ thống: Một feature web app nơi user đăng nhập bằng email/password, sau đó có thể upload ảnh đại diện (JPEG/PNG) được lưu trong object storage và trả về qua CDN URL.
Bước 1 — Chúng ta đang xây dựng cái gì? (Mini DFD)
[User Browser] --(1: credentials)--> [Auth API] --(2: query)--> [User DB]
|
(3: session/JWT)
|
v
[User Browser] --(4: file upload)--> [Upload API] --(5: store)--> [Object Storage]
|
(6: metadata)
v
[Metadata DB]
[User Browser] <--(7: served via CDN)-- [CDN] <--(8: fetch)-- [Object Storage]
Trust boundary: (a) internet ↔ Auth API, (b) internet ↔ Upload API, (c) Upload API ↔ Object Storage, (d) CDN ↔ internet (public read).
Bước 2 — Điều gì có thể sai? (STRIDE theo từng phần tử)
| # | Phần tử | STRIDE | Threat | Mức độ nghiêm trọng |
|---|---|---|---|---|
| 1 | Auth API | Spoofing | Credential stuffing / brute-force đăng nhập bằng danh sách password bị rò rỉ. | Cao |
| 2 | Auth API → JWT | Tampering | Chữ ký JWT không được xác minh ở server-side; attacker sửa claim role thành admin. | Nghiêm trọng |
| 3 | Auth API | Information Disclosure | Thông báo lỗi đăng nhập tiết lộ email có tồn tại hay không (“không tìm thấy user” vs “sai password”), cho phép account enumeration. | Trung bình |
| 4 | Auth API | Repudiation | Không có audit log cho lần đăng nhập thành công/thất bại, IP, hay timestamp — không thể điều tra account takeover về sau. | Trung bình |
| 5 | Upload API | Tampering | Không validate loại file ngoài việc kiểm tra extension ở client-side — attacker upload file .php/.svg chứa script ngụy trang thành .jpg. | Nghiêm trọng |
| 6 | Upload API | Denial of Service | Không giới hạn kích thước file hay rate limit — attacker upload file cực lớn liên tục, làm cạn kiệt storage/bandwidth. | Cao |
| 7 | Upload API | Elevation of Privilege | Endpoint upload không xác minh user đã xác thực có sở hữu profile đang được cập nhật — user A ghi đè ảnh của user B qua ID trong request body (IDOR). | Cao |
| 8 | Object Storage | Information Disclosure | Bucket/container storage bị cấu hình sai thành công khai có thể liệt kê (publicly listable), để lộ toàn bộ file của mọi user kể cả tài liệu nhạy cảm lỡ upload nhầm. | Nghiêm trọng |
| 9 | CDN / Object storage | Tampering | File upload được phục vụ với content-type gốc, browser thực thi file HTML/SVG upload như active content (stored XSS qua file upload). | Cao |
| 10 | Metadata DB | Information Disclosure | Metadata API trả về đường dẫn/key storage nội bộ trong response, hỗ trợ các cuộc tấn công tiếp theo. | Thấp |
Bước 3 — Chúng ta sẽ làm gì với nó? (Mitigation)
| Threat # | Mitigation |
|---|---|
| 1 | Rate-limit số lần đăng nhập, thêm account lockout/backoff, bắt buộc MFA cho tài khoản nhạy cảm, kiểm tra password với cơ sở dữ liệu breach (ví dụ Have I Been Pwned API) khi đăng ký/đổi password. |
| 2 | Luôn xác minh chữ ký JWT ở server-side bằng thư viện đáng tin cậy; không bao giờ tin claim khi chưa xác minh; token thời hạn ngắn + refresh flow. |
| 3 | Dùng thông báo chung chung “email hoặc password không hợp lệ” cho mọi trường hợp đăng nhập thất bại. |
| 4 | Log các sự kiện authentication (thành công/thất bại, IP, user agent, timestamp) vào kho log tập trung, chống giả mạo (xem Monitoring & Logging). |
| 5 | Validate loại file dựa trên nội dung (magic-byte/MIME sniffing), không dựa trên extension; re-encode ảnh ở server-side (loại bỏ payload nhúng); duy trì allowlist các loại file được chấp nhận. |
| 6 | Bắt buộc giới hạn kích thước file tối đa ở server-side; rate-limit upload theo user/IP; dùng pre-signed URL với thời hạn ngắn và ràng buộc kích thước cho upload trực tiếp tới storage. |
| 7 | Xác định user đích từ session/token đã xác thực, không bao giờ từ ID do client cung cấp; thêm kiểm tra authorization ở server-side. |
| 8 | Đặt bucket storage mặc định là private; chỉ phục vụ qua signed CDN URL; bật chặn liệt kê bucket và access logging; liên tục scan cấu hình bucket (xem Bảo mật Cloud). |
| 9 | Bắt buộc Content-Disposition: attachment hoặc phục vụ từ domain riêng không cookie; thiết lập Content-Type chính xác, hạn chế; không cho phép upload SVG/HTML hoặc sanitize chúng; thêm header CSP. |
| 10 | Chỉ trả về URL công khai trong API response; không bao giờ để lộ key/đường dẫn storage nội bộ. |
Bước 4 — Chúng ta đã làm tốt chưa?
- Review lại DFD sau khi triển khai để xác nhận nó khớp với những gì thực sự được xây dựng (developer thường thêm một endpoint “tạm thời” mà không bao giờ được threat-model).
- Thêm test tự động: một security test thử upload file
.svgchứa script tag và assert bị từ chối; một authorization test thử cập nhật ảnh đại diện của user khác và assert trả về 403. - Đưa mọi item “chưa fix ngay” vào risk register với chủ sở hữu và ngày review.
- Thêm threat của feature này vào chu kỳ review threat model định kỳ của team.
Best Practices
- Threat-model thiết kế, không phải code — bạn đang tìm control/giả định trust bị thiếu hoặc sai, không phải lỗi cú pháp; static analysis và code review bắt các lỗi đó riêng.
- Biến nó thành thói quen, không phải sự kiện — nhúng threat modeling nhẹ nhàng vào design doc/RFC template và PR template cho thay đổi nhạy cảm về bảo mật, thay vì một workshop duy nhất trước khi ra mắt.
- Bắt đầu từ DFD, không phải danh sách threat — một bức tranh hệ thống không chính xác sẽ tạo ra threat không tồn tại và bỏ sót threat có thật; thời gian bỏ ra để vẽ diagram đúng sẽ được đền đáp.
- Ưu tiên một cách quyết liệt — không phải threat nào cũng cần fix ngay; dùng risk matrix để quyết định cái nào tiếp theo, và ghi nhận rõ ràng việc chấp nhận rủi ro cho phần còn lại.
- Cho những người hiểu hệ thống tham gia, không chỉ security — developer thường hiểu data flow thực tế và edge case tốt hơn ai hết; security mang đến góc nhìn đối kháng và kỷ luật framework.
- Tự động hóa nơi có thể — các công cụ như OWASP Threat Dragon, pytm, hoặc IriusRisk cho phép lưu model trong version control và tái tạo diagram/danh sách threat khi design-as-code tiến hóa.
- Theo dõi threat đến khi đóng (closure) — mỗi threat cần một ticket, một owner, và một trạng thái; một threat model không gắn với backlog là một tài liệu không ai đọc lần thứ hai.
- Xem lại khi có thay đổi, không chỉ theo lịch — dependency mới, trust boundary mới, loại dữ liệu mới (đặc biệt PII), hoặc incident đều nên kích hoạt việc threat-model lại phần bị ảnh hưởng.
- Dùng STRIDE cho tốc độ, PASTA cho chiều sâu — mặc định dùng STRIDE cho công việc feature hằng ngày; leo thang lên đánh giá kiểu PASTA cho hệ thống giá trị cao, kiến trúc mới, hoặc review theo yêu cầu compliance.
- Coi kết quả threat modeling là đầu vào cho compliance — risk register và threat model thường là bằng chứng bắt buộc cho audit SOC 2, ISO 27001, và tương tự (xem Compliance, Governance & Quản lý rủi ro).
- Đừng bỏ qua câu hỏi số 4 — xác thực mitigation đã thực sự triển khai; một threat model có fix chưa từng được kiểm chứng chỉ tạo cảm giác an toàn giả tạo.
Tài liệu tham khảo
- OWASP Threat Modeling — tổng quan, quy trình, và so sánh phương pháp luận.
- OWASP Threat Modeling Process — hướng dẫn quy trình chi tiết bao gồm DFD và áp dụng STRIDE.
- OWASP Threat Dragon — công cụ threat modeling mã nguồn mở, miễn phí, hỗ trợ STRIDE.
- Microsoft — The STRIDE Threat Model — tài liệu gốc của Microsoft SDL về STRIDE.
- Microsoft Threat Modeling Tool — công cụ miễn phí để xây dựng DFD và tạo báo cáo dựa trên STRIDE.
- VerSprite — PASTA Threat Modeling — tổng quan phương pháp luận PASTA bảy giai đoạn.
- OWASP Top 10 — checklist tham khảo các hạng mục vulnerability ứng dụng web phổ biến nhất.
- Adam Shostack, Threat Modeling: Designing for Security (Wiley, 2014) — cuốn sách kinh điển về framework bốn câu hỏi và STRIDE trong thực tế.
Liên quan: Secure Coding & Bảo mật ứng dụng Web · Compliance, Governance & Quản lý rủi ro
Part of the DevSecOps Roadmap knowledge base.
Overview
Threat modeling is the practice of thinking like an attacker before an attacker does — systematically identifying what could go wrong in a system, how bad it would be, and what to do about it. It is one of the highest-leverage security activities in the SDLC because it happens on paper (or a whiteboard, or a diagram tool), before a single line of code is written or a single dollar is spent building the wrong thing securely.
Risk assessment is the companion discipline: turning a list of threats into a prioritized, actionable set of decisions — which risks to fix now, which to accept, which to transfer (insurance, contracts), and which to monitor.
Why do it early (shift-left)
- Cost asymmetry: a design flaw found in a threat-modeling session costs a conversation; the same flaw found in production costs an incident, a postmortem, customer trust, and possibly a breach disclosure.
- Architecture is hard to patch: you can patch a buffer overflow with a code fix; you generally cannot patch “the service trusts an unauthenticated header” without a redesign. Threat modeling targets exactly the class of bugs that code review and scanners miss — logic and trust-boundary flaws.
- Shared understanding: the exercise itself forces developers, architects, and security engineers to agree on what the system actually does, which frequently surfaces bugs and missing requirements unrelated to security.
- Continuous, not one-off: modern threat modeling is folded into design reviews, PR templates, and sprint planning — not a single workshop before launch that’s never revisited.
The four questions
Adam Shostack’s framework (used by Microsoft’s SDL and widely adopted) reduces threat modeling to four questions, ideally asked as a repeatable loop:
| # | Question | Activity |
|---|---|---|
| 1 | What are we building? | Draw the architecture / data flow diagram (DFD), identify components, trust boundaries, data stores, external entities. |
| 2 | What can go wrong? | Apply a framework (STRIDE, attacker personas, kill chains) to enumerate threats per component/boundary. |
| 3 | What are we going to do about it? | Decide mitigations: fix in design, fix in code, add a control, accept the risk, transfer it. |
| 4 | Did we do a good job? | Retrospective — validate the model against reality, check mitigations actually shipped, re-run when the system changes. |
Question 4 is the most frequently skipped and the most important for making threat modeling a living process rather than a compliance checkbox.
Fundamentals
Core vocabulary
| Term | Definition |
|---|---|
| Asset | Anything of value worth protecting: data, credentials, availability, reputation, intellectual property. |
| Threat | A potential event or actor action that could cause harm to an asset (e.g., “an attacker spoofs a JWT to impersonate a user”). |
| Vulnerability | A weakness that a threat can exploit (e.g., missing signature verification on the JWT). |
| Attack vector / entry point | The path an attacker uses to interact with the system (API endpoint, upload form, network port). |
| Attack surface | The complete set of entry points and vectors an attacker could use — the smaller it is, the less there is to defend. |
| Trust boundary | A point in the system where data or control crosses between components with different levels of trust (e.g., internet → API gateway, user → admin). |
| Risk | The combination of likelihood and impact of a threat being realized — what you actually prioritize and act on. |
| Mitigation / control | A safeguard that reduces likelihood or impact (authentication, input validation, rate limiting, encryption). |
| Residual risk | What remains after mitigations are applied — never zero, must be explicitly accepted by someone accountable. |
Attack surface mapping
Before you can ask “what can go wrong,” you need an accurate picture of the system. Attack surface mapping means enumerating:
- Entry points: every place external input enters the system — public APIs, webhooks, file uploads, message queue consumers, admin panels, CLI tools, third-party integrations, even DNS and TLS termination.
- Trust boundaries: every crossing where the level of trust changes — internet → DMZ, DMZ → internal network, user role → admin role, service A → service B (especially across teams or vendors), container → host.
- Data flows: how data moves and where it’s stored, transformed, or logged — this is where sensitive data exposure typically hides.
- Dependencies: third-party libraries, SaaS integrations, CI/CD pipelines, and infrastructure providers — each is a potential supply-chain entry point (see CI/CD & Supply Chain Security).
Data Flow Diagrams (DFDs) are the standard notation for this. A DFD has four element types:
| Symbol | Element | Meaning |
|---|---|---|
| Circle / rounded rect | Process | A component that transforms data (a service, a function, a microservice). |
| Rectangle | External entity | Something outside your control that interacts with the system (a user, a third-party API). |
| Two parallel lines | Data store | Where data is persisted (database, cache, file system, queue). |
| Arrow | Data flow | Movement of data between elements. |
| Dashed line | Trust boundary | A crossing point where privilege or trust level changes. |
The discipline of drawing the DFD — even informally — is often where the real value of threat modeling comes from: teams discover components they forgot existed, data flows nobody documented, and trust boundaries nobody agreed were boundaries.
Key Concepts
STRIDE
STRIDE is Microsoft’s mnemonic for six threat categories, each mapped to the security property it violates. Apply it per element of the DFD (each process, data store, data flow, and external entity), asking “could this happen here?”
| Category | Violates | Definition | Example |
|---|---|---|---|
| S — Spoofing | Authentication | Pretending to be something/someone you’re not. | An attacker forges a session cookie to log in as another user; a service impersonates another microservice using a stolen API key. |
| T — Tampering | Integrity | Modifying data or code without authorization. | Modifying a price parameter in an unsigned client-side request before it hits the checkout API; altering a JWT payload when the signature isn’t verified. |
| R — Repudiation | Non-repudiation | Denying having performed an action, with no way to prove otherwise. | A user deletes another user’s records and the system has no audit log tying the action to an identity. |
| I — Information Disclosure | Confidentiality | Exposing information to someone not authorized to see it. | An API returns full user objects (including password hashes or internal IDs) when only a display name was needed; verbose error messages leak stack traces. |
| D — Denial of Service | Availability | Degrading or denying service to legitimate users. | An unauthenticated endpoint accepts large file uploads with no size limit, exhausting disk space; a regex vulnerable to ReDoS on user input. |
| E — Elevation of Privilege | Authorization | Gaining capabilities without proper authorization. | A regular user calls an admin-only API endpoint directly because the frontend hides the button but the backend doesn’t check the role. |
How to run a STRIDE session in practice:
- Draw or import the DFD.
- For each element (process, data store, data flow, external entity), go through all six letters and ask “does this threat apply here, and how?”
- Not every letter applies to every element — e.g., a pure data store at rest is rarely a Spoofing target, but is very much a Tampering and Information Disclosure target.
- Record each identified threat with: component, STRIDE category, description, and a rough severity.
- Move to mitigation planning (Key Concepts → Turning threats into backlog items).
A common shortcut for element-type applicability:
| Element type | Typical STRIDE relevance |
|---|---|
| External entity | S, R (can’t tamper with something you don’t own, can’t DoS a person, but can spoof identity and repudiate actions) |
| Process | S, T, R, I, D, E (all six apply) |
| Data store | T, I, D, R (if it lacks change history) |
| Data flow | T, I, D |
PASTA (Process for Attack Simulation and Threat Analysis)
PASTA is a risk-centric, attacker-driven methodology (in contrast to STRIDE’s design-centric, developer-driven approach). It is heavier-weight and typically used for high-value applications, formal risk assessments, or when threat modeling needs to be tied directly to business impact and compliance reporting. It has seven stages:
| Stage | Name | Goal |
|---|---|---|
| 1 | Define objectives | Identify business objectives, compliance requirements, and the assets that matter. |
| 2 | Define technical scope | Enumerate the technical environment: infrastructure, application dependencies, software components. |
| 3 | Application decomposition | Build DFDs, identify entry points, trust boundaries, and assets (similar groundwork to STRIDE’s step 1). |
| 4 | Threat analysis | Analyze threat intelligence, attacker motivations, and known attack patterns relevant to the business context. |
| 5 | Vulnerability & weakness analysis | Correlate identified threats against actual vulnerabilities (scan results, code review findings, CVEs). |
| 6 | Attack modeling / simulation | Model realistic attack trees / attack chains showing how threats and vulnerabilities combine into exploitable paths. |
| 7 | Risk & impact analysis | Quantify business risk, assign residual risk, and recommend countermeasures prioritized by impact. |
PASTA’s value is that it explicitly ties technical threats back to business impact at every stage, which makes it easier to justify investment to non-technical stakeholders. Its cost is that it requires significantly more time, threat intelligence input, and cross-functional involvement than STRIDE.
STRIDE vs PASTA
| Aspect | STRIDE | PASTA |
|---|---|---|
| Approach | Design-centric, developer-driven | Risk-centric, attacker/business-driven |
| Focus | ”What can go wrong in this design” per component | ”What would a real attacker do, and what’s the business impact” |
| Origin | Microsoft SDL | VerSprite (2012, Tony UcedaVélez & Marco Morana) |
| Effort/weight | Lightweight, fast, iterative | Heavyweight, formal, multi-stage |
| Best for | Per-feature / per-sprint threat modeling, day-to-day dev workflow | High-value applications, regulatory/compliance-driven assessments, executive risk reporting |
| Output | List of threats per DFD element with mitigations | Attack simulations, quantified business risk, prioritized countermeasure roadmap |
| Who’s involved | Developers, architects, security champion | Security team, risk/compliance, business stakeholders, threat intel |
| When to use | Every new feature, API, or significant design change | Annual/major-release risk assessments, new high-risk systems, audits |
Other frameworks worth knowing (briefly): DREAD (Damage, Reproducibility, Exploitability, Affected users, Discoverability — a scoring model, often paired with STRIDE, though Microsoft deprecated it internally for being too subjective), Attack Trees (hierarchical breakdown of how a goal could be achieved), LINDDUN (privacy-focused equivalent of STRIDE: Linkability, Identifiability, Non-repudiation, Detectability, Disclosure of information, Unawareness, Non-compliance), and the MITRE ATT&CK matrix (a knowledge base of real-world adversary tactics/techniques, useful for grounding threat scenarios in observed behavior rather than theory).
Threat modeling in the SDLC
| Phase | Activity |
|---|---|
| Design / RFC | Full threat model for new services or major architecture changes: DFD + STRIDE pass, reviewed by security. |
| Sprint planning / per-feature | Lightweight “mini” threat model for new endpoints, new data flows, new third-party integrations — 15–30 minutes, not a full workshop. |
| PR / code review | Threat-modeling checklist embedded in PR templates for security-sensitive changes (auth, payments, PII handling). |
| Pre-release | Re-validate the model against what was actually built; confirm mitigations shipped (question 4: “did we do a good job?”). |
| Post-incident | Update the threat model with the newly discovered attack path — incidents are threats you missed. |
| Periodic review | Revisit models for existing systems on a cadence (e.g., annually, or on major dependency/architecture changes) since attack surface drifts as code changes. |
Who’s involved:
- Developers / tech leads — own the DFD accuracy and implement mitigations.
- Security champions / AppSec engineers — facilitate the session, bring the STRIDE/attacker lens, review coverage.
- Architects — ensure trust boundaries and data flows reflect the real design.
- Product/business stakeholders — needed for PASTA-style business impact scoring, less needed for lightweight STRIDE sessions.
Keeping it lightweight and continuous (the biggest practical failure mode is treating threat modeling as a single heavyweight workshop that never gets revisited):
- Use a template/checklist so a session takes 30–60 minutes, not days.
- Threat-model the delta, not the whole system, for incremental changes — only pull out the full DFD when the architecture actually changes.
- Store the model as code/markdown next to the design doc or repo, version-controlled, so it evolves with the system.
- Automate what you can: threat-modeling tools (e.g., OWASP Threat Dragon, Microsoft Threat Modeling Tool, IriusRisk, pytm) can regenerate diagrams and threat lists from a scriptable model definition, making re-runs cheap.
- Tie identified threats directly into the backlog (see below) so mitigation isn’t a document that gets forgotten.
Risk quantification
Once threats are enumerated, you need to prioritize — you cannot fix everything at once, and some findings aren’t worth fixing at all relative to their cost.
Likelihood × Impact is the base formula for both qualitative and quantitative approaches:
Risk = Likelihood × Impact
Qualitative risk matrix (fast, common in STRIDE-style sessions):
| Impact ↓ / Likelihood → | Low | Medium | High |
|---|---|---|---|
| High | Medium | High | Critical |
| Medium | Low | Medium | High |
| Low | Low | Low | Medium |
- Likelihood factors: attacker skill required, existing controls, exposure (internet-facing vs. internal), whether it’s already been seen exploited elsewhere.
- Impact factors: confidentiality/integrity/availability loss, financial cost, regulatory/legal exposure, reputational damage, blast radius (one user vs. all tenants).
Quantitative approaches attach a monetary/numeric value, useful when justifying investment to finance/executives:
- ALE (Annualized Loss Expectancy) = SLE (Single Loss Expectancy) × ARO (Annualized Rate of Occurrence).
- Example: a data breach costing an estimated $2M (SLE) with an estimated 5% annual likelihood (ARO) → ALE = $100,000/year. This gives a defensible ceiling for how much to spend annually on mitigating that specific risk.
- CVSS (Common Vulnerability Scoring System) — standard for scoring known vulnerabilities (0–10), useful for prioritizing scanner/pentest findings but less suited to novel design-level threats since it’s built around known CVE-style vulnerabilities.
- FAIR (Factor Analysis of Information Risk) — a more rigorous quantitative model that breaks risk into loss event frequency and loss magnitude with probability distributions, popular in mature risk-management programs (see Compliance, Governance & Risk Management).
Risk treatment options — once a risk is scored, decide:
| Option | Meaning |
|---|---|
| Mitigate | Reduce likelihood or impact via a control (the default for anything above your risk-acceptance threshold). |
| Accept | Formally acknowledge and sign off on the residual risk (must be a named, accountable owner — not silence). |
| Transfer | Shift the financial impact elsewhere (cyber insurance, contractual indemnification with a vendor). |
| Avoid | Eliminate the risk by removing the feature/component/dependency entirely. |
Risk register: the artifact that tracks all of this over time — typically a table/spreadsheet or a field in a GRC tool with columns like: ID, description, asset, threat category, likelihood, impact, risk score, treatment decision, owner, status, due date, last reviewed date. This is the living record auditors and leadership actually look at; a threat model that never makes it into a risk register tends to be forgotten.
OWASP Top 10 as a threat-modeling checklist
The OWASP Top 10 is not a substitute for threat modeling, but it’s an excellent checklist to sanity-check coverage once you’ve enumerated threats via STRIDE/PASTA — especially for web applications, since it captures the most commonly exploited vulnerability classes in the wild:
- Broken Access Control, Cryptographic Failures, Injection, Insecure Design, Security Misconfiguration, Vulnerable & Outdated Components, Identification & Authentication Failures, Software & Data Integrity Failures, Security Logging & Monitoring Failures, Server-Side Request Forgery (SSRF).
Cross-check: for each STRIDE threat you identified, ask “does this map to an OWASP Top 10 category, and if so, is there a known standard mitigation?” Deep, code-level coverage of these categories (with concrete secure-coding patterns) is covered in Secure Coding & Web Application Security — this note stays at the design/threat-identification level.
Turning threats into backlog items / security requirements
A threat model that lives only in a document is close to worthless. Each identified threat should become one of:
- A security requirement written before/during design (e.g., “all admin endpoints must verify role server-side, never trust client-side UI hiding”).
- A backlog ticket with the same rigor as a functional bug: reproduction/scenario, severity, affected component, suggested fix, acceptance criteria.
- An explicit risk-acceptance record in the risk register, with a named owner and review date, if it won’t be fixed now.
- A test case — ideally an automated one (a security unit/integration test, a DAST rule, a policy-as-code check) so regression is caught automatically going forward.
A simple mapping template:
| Threat ID | STRIDE Category | Component | Description | Likelihood | Impact | Risk | Mitigation | Backlog ticket | Owner | Status |
|---|
Worked Example: “User Login + File Upload” Feature
System description: A web app feature where a user logs in with email/password, then can upload a profile picture (JPEG/PNG) that’s stored in object storage and served back via a CDN URL.
Step 1 — What are we building? (Mini DFD)
[User Browser] --(1: credentials)--> [Auth API] --(2: query)--> [User DB]
|
(3: session/JWT)
|
v
[User Browser] --(4: file upload)--> [Upload API] --(5: store)--> [Object Storage]
|
(6: metadata)
v
[Metadata DB]
[User Browser] <--(7: served via CDN)-- [CDN] <--(8: fetch)-- [Object Storage]
Trust boundaries: (a) internet ↔ Auth API, (b) internet ↔ Upload API, (c) Upload API ↔ Object Storage, (d) CDN ↔ internet (public read).
Step 2 — What can go wrong? (STRIDE per element)
| # | Element | STRIDE | Threat | Severity |
|---|---|---|---|---|
| 1 | Auth API | Spoofing | Credential stuffing / brute force login using leaked password lists. | High |
| 2 | Auth API → JWT | Tampering | JWT signature not verified server-side; attacker modifies role claim to admin. | Critical |
| 3 | Auth API | Information Disclosure | Login error messages reveal whether an email exists (“user not found” vs “wrong password”), enabling account enumeration. | Medium |
| 4 | Auth API | Repudiation | No audit log of failed/successful login attempts, IP, or timestamp — can’t investigate account takeover later. | Medium |
| 5 | Upload API | Tampering | No file-type validation beyond client-side extension check — attacker uploads a .php/.svg with embedded script disguised as .jpg. | Critical |
| 6 | Upload API | Denial of Service | No file size limit or rate limit — attacker uploads huge files repeatedly, exhausting storage/bandwidth. | High |
| 7 | Upload API | Elevation of Privilege | Upload endpoint doesn’t verify the authenticated user owns the profile being updated — user A overwrites user B’s picture via ID in the request body (IDOR). | High |
| 8 | Object Storage | Information Disclosure | Storage bucket/container misconfigured as publicly listable, exposing all users’ uploaded files including any accidentally-uploaded sensitive documents. | Critical |
| 9 | CDN / Object storage | Tampering | Uploaded file served with original content-type, browser executes an uploaded HTML/SVG file as active content (stored XSS via file upload). | High |
| 10 | Metadata DB | Information Disclosure | Metadata API returns internal storage paths/keys in API responses, aiding further attacks. | Low |
Step 3 — What do we do about it? (Mitigations)
| Threat # | Mitigation |
|---|---|
| 1 | Rate-limit login attempts, add account lockout/backoff, enforce MFA for sensitive accounts, check passwords against breach corpora (e.g., Have I Been Pwned API) at signup/change. |
| 2 | Always verify JWT signature server-side with a vetted library; never trust claims without verification; short-lived tokens + refresh flow. |
| 3 | Use a generic “invalid email or password” message for all login failures. |
| 4 | Log authentication events (success/failure, IP, user agent, timestamp) to a tamper-evident, centralized log store (see Monitoring & Logging). |
| 5 | Validate file type by content (magic-byte/MIME sniffing), not extension; re-encode images server-side (strips embedded payloads); maintain an allowlist of accepted types. |
| 6 | Enforce max file size server-side; rate-limit uploads per user/IP; use pre-signed URLs with short expiry and size constraints for direct-to-storage uploads. |
| 7 | Derive the target user from the authenticated session/token, never from a client-supplied ID; add authorization check server-side. |
| 8 | Set storage bucket to private by default; serve only via signed CDN URLs; enable bucket-listing denial and access logging; scan bucket configuration continuously (see Cloud Security). |
| 9 | Force Content-Disposition: attachment or serve from a separate cookieless domain; set correct, restrictive Content-Type; disallow SVG/HTML uploads or sanitize them; add CSP headers. |
| 10 | Return only public-facing URLs in API responses; never leak internal storage keys/paths. |
Step 4 — Did we do a good job?
- Re-review the DFD after implementation to confirm it matches what was actually built (developers often add a “just for now” endpoint that never gets threat-modeled).
- Add automated tests: a security test that attempts to upload an
.svgwith a script tag and asserts rejection; an authorization test that attempts to update another user’s profile picture and asserts a 403. - File all “won’t fix now” items in the risk register with an owner and review date.
- Add this feature’s threats to the team’s recurring threat-model review cadence.
Best Practices
- Threat-model the design, not the code — you’re looking for missing/incorrect controls and trust assumptions, not syntax bugs; static analysis and code review catch those separately.
- Make it a habit, not an event — bake lightweight threat modeling into design docs/RFC templates and PR templates for security-sensitive changes, rather than a single pre-launch workshop.
- Start from the DFD, not the threat list — an inaccurate picture of the system produces threats that don’t exist and misses ones that do; time spent getting the diagram right pays off.
- Prioritize ruthlessly — not every threat gets fixed immediately; use a risk matrix to decide what’s next, and record explicit risk acceptance for the rest.
- Involve the people who know the system, not just security — developers usually know the real data flows and edge cases better than anyone; security brings the adversarial lens and framework discipline.
- Automate where possible — tools like OWASP Threat Dragon, pytm, or IriusRisk let you keep the model in version control and regenerate diagrams/threat lists as the design-as-code evolves.
- Track threats to closure — every threat needs a ticket, an owner, and a status; a threat model that isn’t connected to the backlog is a document nobody reads twice.
- Revisit on change, not just on a calendar — new dependency, new trust boundary, new data type (especially PII), or incident should all trigger a targeted re-model of the affected area.
- Use STRIDE for velocity, PASTA for depth — default to STRIDE for day-to-day feature work; escalate to a PASTA-style assessment for high-value systems, new architectures, or compliance-driven reviews.
- Treat threat modeling output as input to compliance — risk registers and threat models are frequently required evidence for SOC 2, ISO 27001, and similar audits (see Compliance, Governance & Risk Management).
- Don’t skip question 4 — validate mitigations actually shipped; a threat model whose fixes were never verified is a false sense of security.
References
- OWASP Threat Modeling — overview, process, and methodology comparisons.
- OWASP Threat Modeling Process — detailed process guide including DFDs and STRIDE application.
- OWASP Threat Dragon — free, open-source threat-modeling tool supporting STRIDE.
- Microsoft — The STRIDE Threat Model — original Microsoft SDL documentation of STRIDE.
- Microsoft Threat Modeling Tool — free tool for building DFDs and generating STRIDE-based reports.
- VerSprite — PASTA Threat Modeling — overview of the seven-stage PASTA methodology.
- OWASP Top 10 — reference checklist of the most common web application vulnerability categories.
- Adam Shostack, Threat Modeling: Designing for Security (Wiley, 2014) — the canonical book on the four-question framework and STRIDE in practice.
Related: Secure Coding & Web Application Security · Compliance, Governance & Risk Management