Course outline

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.

About 4 min readContent reviewed
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.

json A fictional requirement with evidence boundaries
{"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.

python Check refusal category and unchanged protected state
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")
Expected output
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.

Official references