Secure software development: SDLC, design principles and threat modeling
You learn to build security into every phase of the life cycle instead of adding it to the code afterwards, the Saltzer-Schroeder design principles, threat modeling with STRIDE, and security requirements. The exam gives a scenario and asks 'which principle is violated'.
Most security holes are not “badly coded lines” but badly made decisions: nobody thought about authorization, what happens on error was never defined, the admin panel was left open to the Internet. This week you learn how to put security inside the software life cycle (SDLC). The typical exam question is this: a short scenario is given and you are asked “which principle is violated?” or “which STRIDE category?”. A DREAD or risk calculation may also appear.
Golden rules:
- Security is not a phase, it is every phase. It starts at requirements and doesn’t end at maintenance.
- The default answer is “no”. If you are not sure, deny access.
- Check every access. Checking once and forgetting is not enough.
- Find threats systematically. STRIDE makes you question letter by letter and catches what you wouldn’t think of.
- Rank risk by number. You can’t fix everything at once.
Secure SDLC (secure software development life cycle)
You get a secure SDLC by adding the security work to be done in each phase of the classic SDLC. Microsoft SDL, OWASP SAMM and BSIMM are different frameworks of this idea.
| Phase | Security work | Output |
|---|---|---|
| Requirements | security requirements, misuse cases, compliance (GDPR, KVKK) | a list of measurable requirements |
| Design | threat modeling, attack surface analysis, secure architecture | DFD + threat list + mitigations |
| Implementation | secure coding standards, code review, SAST | clean static analysis report |
| Verification (test) | DAST, fuzzing, penetration testing | findings list, closed vulnerabilities |
| Release | final security review, incident response plan | approval |
| Maintenance | patch management, monitoring, dependency tracking | an up-to-date system |
Why at the very start? Fixing a design flaw in the design phase is a diagram change. If the same flaw is found in a live system, code, data migration, customer notification and loss of reputation follow. The “cost of a late-found defect multiplies” curve in the literature is even steeper for security.
PITFALL · the “we’ll do a pentest at the end” approach. A penetration test shows the hole it finds, but fixing a design flaw afterwards is expensive. A pentest does not replace a secure SDLC, it is its final check.
Secure design principles (Saltzer & Schroeder)
The eight principles written by Saltzer and Schroeder in 1975 are still exam favorites today. We also add defense in depth, which is often included alongside them.
| Principle | In one sentence | Example violation |
|---|---|---|
| Least privilege | Each component runs with just enough privilege to do its job. | The web server runs as root. |
| Fail-safe defaults | The default decision is to deny; permission is given explicitly. | A catch that allows access on error. |
| Complete mediation | Every access to every object is checked. | Authorization is checked only at login. |
| Economy of mechanism | The security mechanism should be simple and small. | Your own 5000-line encryption code. |
| Open design | Security does not rely on the secrecy of the design. | “Nobody knows our algorithm, so it’s secure.” |
| Separation of privilege | A critical action requires more than one condition. | A single admin can delete the production database alone. |
| Least common mechanism | Mechanisms shared among users are reduced. | All tenants sharing the same temp directory. |
| Psychological acceptability | Security must be usable, or it gets bypassed. | A 20-character password that changes daily, notes stuck to screens. |
| Defense in depth | Several layers independent of each other. | Relying only on the firewall and using plaintext HTTP on the internal network. |
Fail-safe defaults: how it looks in code
// BAD: allows everyone when the service crashes
boolean canRead(User u, File f) {
try { return acl.allows(u, f, READ); }
catch (Exception e) { return true; }
}
// GOOD: deny when uncertain, log the event
boolean canRead(User u, File f) {
try { return acl.allows(u, f, READ); }
catch (Exception e) {
log.warn("ACL check failed, denying", e);
return false;
}
}
The same idea applies to firewall rules: a “deny all” rule comes at the end, and what is allowed is written one by one (allowlist).
Defense in depth and probability
With independent layers, the probabilities of the attacker getting through each one are multiplied. Example: if the probability of getting past the WAF is 0.3, getting past in-application validation is 0.2, and getting past the database privilege restriction is 0.1, the probability of getting through all of them is:
Layers that look weak one by one are strong together. But note: if the layers share the same weakness (the same password, the same library), they are not independent, and the product is invalid.
TIP · how to find the principle. If the scenario has “too much privilege”, it is least privilege; “allow on error”, fail-safe; “checked once”, complete mediation; “secret algorithm”, open design; “one person is enough”, separation of privilege.
Threat modeling
Threat modeling looks for answers to four questions: What are we building? What can go wrong? What are we going to do about it? Did we do a good job?
Step 1: the data flow diagram (DFD)
You draw the system with four elements:
| Element | Meaning | Example |
|---|---|---|
| External entity | an actor outside the system | a user, a payment provider |
| Process | code that processes data | a web application, an API |
| Data store | where data rests | a database, a log file |
| Data flow | movement of data between them | an HTTPS request, a SQL query |
On top of these you draw trust boundary lines: between the Internet and the server, between the application and the database. Most threats appear in the flows that cross these boundaries, because one side should not trust the other’s data.
Step 2: STRIDE
You question each DFD element with six threat categories:
| Letter | Threat | Property broken | Typical mitigation |
|---|---|---|---|
| S | Spoofing (identity forgery) | Authentication | strong authentication, MFA |
| T | Tampering | Integrity | MAC, signature, access control |
| R | Repudiation | Non-repudiation | audit log, digital signature |
| I | Information disclosure | Confidentiality | encryption, least privilege |
| D | Denial of service | Availability | rate limiting, resource quota |
| E | Elevation of privilege | Authorization | authorization checks, sandbox |
Example: for the “User → Login API” flow, S: logging in with someone else’s password; T: the request is modified on the way; R: the user denies logging in; I: the error message says “this email is not registered” and leaks the existence of the user; D: thousands of login attempts per second; E: trusting the role=admin field in the request.
Step 3: rank the risks
There are two common methods.
Risk = likelihood × impact. Likelihood 0-1, impact 1-10:
| Threat | Likelihood | Impact | Risk |
|---|---|---|---|
| T1 spoofing | 0.2 | 8 | 1.6 |
| T2 information disclosure | 0.5 | 6 | 3.0 |
| T3 DoS | 0.7 | 3 | 2.1 |
Order: T2 > T3 > T1. T1, with the greatest impact, comes last, because its likelihood is low.
DREAD. Five categories are scored 0-10 and averaged: Damage, Reproducibility, Exploitability, Affected users, Discoverability.
| Threat | D | R | E | A | D | Average |
|---|---|---|---|---|---|---|
| SQL injection in the login form | 9 | 8 | 7 | 10 | 8 | 8.4 |
| Tampering with the log file | 6 | 5 | 4 | 3 | 5 | 4.6 |
| Verbose error messages | 3 | 9 | 8 | 6 | 9 | 7.0 |
DREAD is subjective, so Microsoft has dropped it internally, but it still appears in textbooks and exams. CVSS is a more standard alternative.
Step 4: mitigation and verification
For each threat there are four options: mitigate, eliminate (remove the feature), transfer (insurance, a third party), accept (a documented decision). Then it is verified by testing that the mitigation really works.
Security requirements and misuse cases
A functional requirement says “what the system should do”. A security requirement says “what the system must not allow and how it must be protected”. A good security requirement is measurable and testable.
| Bad (vague) | Good (testable) |
|---|---|
| “The system must be secure.” | “Passwords must be stored with bcrypt (cost ≥ 12).” |
| “Brute force must be prevented.” | “The account must be locked for 15 minutes after 5 failed logins.” |
| “Data must be protected.” | “All client-server traffic must be encrypted with TLS 1.2+.” |
The way to find these requirements is to write misuse cases. In a normal use case the actor is “Customer” and the scenario is “Logs into their account”. In a misuse case the actor is “Attacker” (misactor) and the scenario is “Automatically tries a list of passwords”. A misuse case “threatens” the use case; a countermeasure “mitigates” the misuse case. Each misuse case yields a security requirement.
PITFALL · not writing a security requirement like a functional one. “Admins can delete users” is functional. The security side: “Only the admin role can delete, and every deletion is logged with who did it.” The second sentence is testable and closes the E and R threats.
Common mistakes
| Wrong idea | Correct |
|---|---|
| Threat modeling is done in the test phase | It is done in design, then updated |
| Tampering → confidentiality | Integrity. What breaks confidentiality is Information disclosure |
| Repudiation → authentication | Non-repudiation; the countermeasure is logs and signatures |
| Allowing access on error is user-friendly | A fail-safe defaults violation; default deny |
| Checking once at login is enough | Complete mediation: check on every access |
| A secret algorithm is extra security | Open design: only the key should be secret |
| Fix the highest-impact threat first | Risk = likelihood × impact; take likelihood into account too |
| “The system must be secure” is a requirement | Not measurable; write a testable sentence |
| Layers always multiply probabilities | Only if independent; a shared weakness breaks the product |
Test yourself
Exam-style questions. Solve them on paper first, then reveal the answer.
A web server process runs as root even though it only needs to read files in /var/www and listen on one port. Which secure design principle is violated?
- Open design
- Least privilege
- Economy of mechanism
- Psychological acceptability
Show answer
The process has more privilege than the minimum it needs to do its job. The least privilege principle forbids exactly this. If the server is compromised, the attacker also gets root privileges. The right way: run it with a separate unprivileged user and give read-only permission.
In the STRIDE model, a threat of type Tampering violates which security property?
- Confidentiality
- Availability
- Integrity
- Authentication
Show answer
STRIDE maps each letter to a property. Tampering is modifying data or code without permission, and the property it breaks is integrity. Confidentiality corresponds to Information disclosure, availability to DoS, and authentication to Spoofing.
A user transfers money and later claims 'I never made that transfer', and the system has no way to prove otherwise. Which STRIDE category is this, and which property is missing?
- Spoofing / authentication
- Repudiation / non-repudiation
- Tampering / integrity
- Elevation of privilege / authorization
Show answer
The user denies an action they performed, and the system can't prove it. This is a repudiation threat. The missing property is non-repudiation. The fix: reliable, tamper-proof audit logs and, where needed, digital signatures.
Security should not depend on keeping the design or the algorithm secret; only keys and passwords should be secret. Which principle is this?
- Open design
- Complete mediation
- Least common mechanism
- Fail-safe defaults
Show answer
Open design is the general form of Kerckhoffs's principle in cryptography. Relying on the design staying secret (security through obscurity) is weak, because code leaks and gets reverse engineered. Only the key should remain secret.
A threat is scored with DREAD as Damage = 8, Reproducibility = 6, Exploitability = 7, Affected users = 9, Discoverability = 5. What is its DREAD risk score (simple average)?
Show answer
The DREAD score is the average of the five categories..
On a 0-10 scale, 7 counts as high, so this threat is prioritized.
Threat T1 has likelihood 0.3 and impact 9. Threat T2 has likelihood 0.6 and impact 5. Using risk = likelihood × impact, which threat should be fixed first, and what are the two risk values?
Show answer
, .
Although its impact is smaller, T2 is twice as likely, and its total risk is greater. Looking only at impact and choosing T1 is the typical mistake.
Which secure design principle does the code below violate?
boolean canDelete(User u, Doc d) {
try {
return acl.check(u, d, "DELETE");
} catch (Exception e) {
return true; // ACL service down, let it through
}
}- Least privilege
- Fail-safe defaults
- Open design
- Separation of privilege
Show answer
In case of an error the code allows access. According to the fail-safe defaults principle, the default decision must be "deny", and access should open only when explicitly allowed. That everyone can delete every document when the ACL service crashes is exactly a violation of this principle. The fix: return false; in the catch block and log the event.
An application checks a user's permissions only once at login and caches the result for the whole session. An admin revokes the user's access, but the user keeps working for hours. Which principle is violated?
- Economy of mechanism
- Complete mediation
- Psychological acceptability
- Open design
Show answer
Complete mediation: authority must be re-checked on every access to every object. Keeping the result in a cache and never looking again lets access continue even after the permission is revoked. If a cache is used, it must be short-lived and be invalidated when permissions change.
In which SDLC phase is threat modeling most cost-effective to perform?
- Requirements and design
- Deployment
- Maintenance
- After a penetration test fails
Show answer
Threat modeling is done while the architecture is taking shape. Fixing a design flaw in the design phase is a change to a drawing. If the same flaw is found after it goes live, it needs re-architecture, patches and incident response; the cost multiplies.
How does a misuse case differ from a normal use case?
- It describes a feature the customer forgot to request
- It describes how an attacker (misactor) could abuse the system, and drives security requirements
- It is a use case with no actors
- It is a test case written after deployment
Show answer
A use case describes what the system should do. A misuse (abuse) case describes how a malicious actor could abuse the system. Each misuse case turns into a countermeasure, that is, a security requirement: e.g. "brute-force password guessing" → "the account is locked for 15 min after 5 failed attempts".
Which STRIDE threat is mitigated mainly by authorization checks?
- Spoofing
- Information disclosure
- Denial of service
- Elevation of privilege
Show answer
Elevation of privilege: a user being able to do something they are not permitted to do. Its counterpart is authorization. The counterpart of Spoofing is authentication, of Information disclosure confidentiality, and of DoS availability.
A system has three independent defense layers. An attacker bypasses them with probabilities 0.1, 0.2 and 0.05 respectively. Assuming independence, what is the probability that the attacker gets through all three layers?
Show answer
The layers are independent and the attacker has to get through all of them, so the probabilities are multiplied:.
The probability that at least one layer holds is . This is where the strength of defense in depth comes from. Pitfall: if the layers share the same weakness (e.g. the same password), the independence assumption collapses.
Verification: DREAD averages, risk = likelihood × impact products and layered defense probabilities were computed with node (verify/SEN2008/13.mjs). Conceptual answers were checked against the Saltzer-Schroeder (1975) principles and the Microsoft STRIDE definitions.