Secure Software Development / Basic: outcomes, models, and decisions / Lesson 3
Write verifiable security requirements
Translate a broad security concern into a bounded rule, refusal behavior, and evidence plan.
On this page
Lesson goals
- Define subject, resource, action, condition, and protected outcome.
- Use a standard as a versioned reference without inventing requirement numbers.
Replace adjectives with observable rules
“The export must be secure” leaves implementation and review without a shared acceptance rule. A more useful requirement says that an organizer may export only registrations for an assigned workshop, with permitted fields, and that refusal produces no export artifact. This names the subject, resource, action, condition, and outcome. Add lifecycle assumptions such as assignment changes before download when relevant. Keep the rule independent of a framework helper name so another implementation can satisfy the same property. A requirement should explain what must hold without prescribing irrelevant internal mechanics.
Make the rule reviewable as data
A compact requirement record can link policy to its planned observations. The first example includes allowed and denied cases and explicitly names the unchanged-state condition. These are classroom identifiers, not ASVS or SSDF requirement numbers. When adopting a published standard, pin the version and cite its actual requirement text or identifier accurately in the approved project record. Tailor applicability and keep the rationale. Checking a box against an unrelated control adds administrative appearance without evidence that the product’s actual disclosure boundary was considered.
{"id":"LAB-EXPORT-01","rule":"assigned-organizer-may-export-permitted-fields","allowedCase":"assigned-organizer","deniedCase":"different-organizer","denialInvariant":"no-export-artifact","evidenceBoundary":"handler-and-owned-store-fixture","status":"planned"}
This non-runnable record is a requirement plan. Its LAB identifier is local to the course. It does not certify compliance, execute an acceptance case, or prove that the storage and handler are correctly integrated.
Define rejection as carefully as acceptance
A denied request should have a documented public response and preserve protected state. Decide whether the public policy reveals that a workshop exists, and keep diagnostic detail separate from user-facing errors. The local program models a refusal observation with no artifact and checks both properties. A real implementation may include an approved audit event, so distinguish protected business mutation from expected ancillary logging. Requirements that merely say return forbidden can miss a job or notification created before the permission check. Observe the side effects the rule actually protects.
before = {"exports": [], "notifications": []}
after = {"exports": [], "notifications": []}
response = {"category": "NOT_PERMITTED"}
assert response["category"] == "NOT_PERMITTED"
assert after == before
assert len(after["exports"]) == 0
print("denial contract observation checked")
denial contract observation checked
The complete program evaluates a declared synthetic observation. It performs no authorization or storage operation. The error category is a fictional stable machine marker, and actual disclosure mapping belongs to the selected API contract.
Assign the right verification method
Different requirements need different evidence. A pure policy rule can be modeled with local fixtures; middleware integration needs an approved component test; a human recovery procedure needs a reviewed exercise and decision record. Do not demand that every requirement become a unit test, and do not use a policy document as evidence of runtime enforcement. Specify what is observed, what is replaced, and what remains untested. Include at least one legitimate allowed case so a defense that rejects everyone cannot satisfy the requirement accidentally. Precision supports useful verification rather than maximum test counts.
Maintain requirements as behavior changes
A new export destination, tenant model, or background workflow can invalidate an old acceptance plan. Review requirements with the design change, not after implementation is complete. Preserve the old supported behavior until an explicit migration decision changes it. Record approved exceptions with a reason, accountable owner, compensating controls where justified, and a review point. An exception is not a passing test and must remain visible in the release evidence. A short, maintained set of relevant rules is more useful than a large copied standard whose applicability nobody can explain.
Common errors and fixes
A requirement says only use best practices
- Why it happens
- No observable outcome or boundary is defined.
- How to fix it
- Name the subject, action, resource, condition, and protected result.
- Prevent it next time
- Review acceptance and denial observations before implementation.
Rejecting every organizer satisfies the test
- Why it happens
- Only denied cases are included.
- How to fix it
- Add a legitimate assigned-organizer success with exact permitted fields.
- Prevent it next time
- Pair positive and negative evidence for important policies.
An invented control number is attributed to ASVS
- Why it happens
- A local identifier is confused with a published requirement.
- How to fix it
- Label classroom ids locally and cite actual versioned standard references accurately.
- Prevent it next time
- Check standard mappings during review.
Check your understanding
1. Rewrite “exports must protect privacy” as one testable rule.
Show worked solution
For the fictional service, only an assigned organizer may receive the approved registration projection, and denied requests create no export or notification. Add an allowed fixture, a different-organizer fixture, exact field expectations, and the actual boundary to be verified. Keep retention as a separate requirement if it needs different evidence.
2. A storage integration check is planned but not run. Can the requirement be marked verified?
Show worked solution
No. Record the local policy evidence separately and retain the storage boundary as pending. A requirement can have partial evidence without being fully verified. The release owner may make an accountable risk decision, but the report must not transform absence of observation into a pass.
Key takeaways
- Observable rules connect design and verification.
- Denied behavior includes protected state and side effects.
- Published standards need accurate versioned mappings.