Free Ebook cover Practical Cryptography for Developers: Build, Break, and Secure Real Systems

Practical Cryptography for Developers: Build, Break, and Secure Real Systems

New course

11 pages

Secure Architecture Checklists for Web, Mobile, and Backend

Capítulo 8

Estimated reading time: 0 minutes

+ Exercise

What a “secure architecture checklist” is (and is not)

A secure architecture checklist is a repeatable set of verifications you can apply to a system design and its implementation to catch common security gaps before they become incidents. It is not a substitute for engineering judgment, code review, or risk analysis; it is a forcing function that makes teams ask the same critical questions every time they ship a feature, integrate a service, or change infrastructure. In practice, a good checklist is scoped (web vs mobile vs backend), tied to concrete evidence (config snippets, logs, dashboards, test results), and mapped to ownership (who fixes what). The goal is to reduce “unknown unknowns” by turning them into explicit, testable requirements.

Because this course already covered cryptographic primitives and protocol-level details, this chapter focuses on architecture-level checks: boundaries, trust assumptions, deployment posture, operational controls, and the “glue” where real systems fail (misconfigurations, missing validation, unsafe defaults, and weak observability). You should treat each checklist item as something you can verify with a screenshot, a command output, a policy file, or an automated test.

How to use checklists without slowing delivery

To keep checklists from becoming shelfware, integrate them into your delivery pipeline. First, split items into “design-time” (must be answered in an ADR or design doc) and “ship-time” (must be proven by CI/CD, scanning, or runtime checks). Second, tag each item with severity and frequency: some checks are per feature (e.g., new external integration), others are per release (e.g., dependency updates), and some are continuous (e.g., alerting). Third, make evidence mandatory: a checklist item is not “done” until a link to evidence exists (policy, test, dashboard, or config). Finally, automate what you can: configuration linting, IaC policy-as-code, SAST/DAST, container scanning, secret scanning, and runtime posture checks.

Step-by-step: turning a checklist into a gate

  • Define a “Definition of Done: Security” section in your PR template with 8–15 high-value items.
  • Create a longer architecture checklist used in design reviews (30–60 items) and store it with the design doc.
  • For each ship-time item, add a CI job that fails when evidence is missing (e.g., no CSP header test, no SBOM, no container scan).
  • For each continuous item, add an SLO/alert and link it in the checklist (e.g., “WAF blocks above baseline triggers alert”).
  • Review the checklist quarterly: remove items that never catch issues; add items based on incidents and near-misses.

Cross-cutting checklist: applies to web, mobile, and backend

Trust boundaries and data classification

Most architecture failures come from unclear boundaries: what runs in a trusted network, what runs on user devices, what is exposed to the internet, and what data is sensitive. Classify data (public, internal, confidential, regulated) and map it to flows. Verify that every flow has an explicit boundary crossing and a control at that crossing (validation, authorization, rate limiting, auditing).

  • Data classification exists and is referenced in schemas and API docs.
  • Data flow diagram identifies entry points, external dependencies, and storage systems.
  • Every boundary crossing has: authentication context, authorization decision point, input validation, and logging.
  • Secrets and credentials are never treated as “data”; they have separate handling and rotation policies.

Configuration and secrets hygiene

Architecture should assume configuration will drift and secrets will leak unless you design against it. Verify that configuration is centralized, versioned, and validated, and that secrets are stored in a managed secret store with rotation and least privilege. Avoid “shared admin tokens” and long-lived credentials in CI.

Continue in our app.

You can listen to the audiobook with the screen off, receive a free certificate for this course, and also have access to 5,000 other free online courses.

Or continue reading below...
Download App

Download the app

  • All environments (dev/stage/prod) are defined in IaC; no manual snowflakes.
  • Secret store is used (cloud secret manager, Vault, etc.); no secrets in git, images, or build logs.
  • Rotation exists for service credentials; emergency revoke procedure is documented and tested.
  • Principle of least privilege is enforced via IAM roles, not shared accounts.

Dependency, build, and supply-chain posture

Modern systems are assembled from dependencies and build pipelines. Your architecture checklist must include build integrity and provenance: what you build, how you build it, and how you know it wasn’t tampered with. This is not about a specific tool; it’s about verifiable controls.

  • SBOM is generated for releases and stored with artifacts.
  • Dependencies are pinned and updated on a schedule; critical patches have an SLA.
  • CI runners are isolated; build secrets are scoped; PRs from forks cannot access secrets.
  • Artifacts are signed or otherwise integrity-protected; deployment only accepts trusted artifacts.

Observability and incident readiness

Security architecture includes the ability to detect and respond. Verify that logs are structured, correlated, and protected from tampering; that you can answer “who did what, when, and from where” for sensitive actions; and that you can contain incidents quickly.

  • Audit logs exist for auth events, privilege changes, data export, and admin actions.
  • Logs include request IDs, user IDs (or subject), device/app version, and source metadata.
  • Log retention meets business/regulatory needs; access to logs is restricted and audited.
  • Runbooks exist for key incident types (credential leak, data exposure, abuse spike, compromised host).

Web application checklist (browser-based clients)

Browser attack surface: enforce safe defaults

Web apps inherit a hostile execution environment: untrusted scripts, extensions, and cross-origin interactions. Your architecture should reduce what the browser is allowed to do by default and make unsafe actions explicit. This is primarily about headers, origin boundaries, and minimizing ambient authority.

  • Content Security Policy (CSP) is defined and tested; no unsafe-inline unless justified with nonces/hashes.
  • Strict-Transport-Security (HSTS) is enabled with appropriate max-age and includeSubDomains when safe.
  • Referrer-Policy is set to avoid leaking sensitive URLs.
  • X-Content-Type-Options and frame protections (frame-ancestors via CSP) are configured.
  • Cross-Origin Resource Sharing (CORS) is explicit: no wildcard origins for authenticated endpoints.

Input handling and output encoding at architectural boundaries

Even if individual endpoints validate input, architecture should define where validation happens and how it is shared. Establish a single validation layer (API gateway, shared middleware, or schema validation) and a single output encoding strategy in templates/components. The checklist should ensure you are not relying on “developer remembers to sanitize.”

  • All external inputs are validated against schemas (OpenAPI/JSON schema) at the edge or service boundary.
  • File uploads have size limits, type allowlists, malware scanning hooks, and storage isolation.
  • Templating uses auto-escaping by default; raw HTML rendering requires explicit review.
  • Redirects use allowlists or signed state to prevent open redirect abuse.

Frontend build and third-party scripts

Third-party scripts and frontend dependencies are a major architectural risk because they execute with your origin’s privileges. Prefer self-hosting critical libraries, minimize third-party tags, and isolate what you can. Treat analytics and marketing tags as privileged code.

  • Inventory of third-party scripts exists; each has an owner and business justification.
  • Subresource Integrity (SRI) is used for any externally hosted static assets when feasible.
  • Third-party iframes are sandboxed; postMessage usage is validated with strict origin checks.
  • Frontend build pipeline is locked down (dependency pinning, integrity checks, restricted publish rights).

Step-by-step: CSP rollout that doesn’t break production

  • Start with Content-Security-Policy-Report-Only and a reporting endpoint.
  • Deploy to a small percentage of traffic; collect violation reports and group by directive.
  • Eliminate inline scripts/styles; move to bundled assets or use nonces for unavoidable inline code.
  • Lock down script-src first (highest value), then connect-src, img-src, and frame-src.
  • Switch to enforcing CSP; keep reporting enabled for ongoing drift detection.

Mobile application checklist (iOS/Android clients)

Client trust model: assume the device is hostile

Mobile apps run on devices you do not control. Users can jailbreak/root, attach debuggers, intercept traffic, and modify local storage. Architecture must treat the mobile app as an untrusted client: it can help with UX and local protections, but it cannot be the source of truth for authorization, pricing, entitlements, or anti-abuse decisions.

  • Server enforces all authorization and business rules; client-side checks are treated as advisory.
  • API requests are validated server-side for replay/abuse patterns (timestamps, idempotency keys where appropriate).
  • Feature flags and entitlements are verified on the server, not only in the app.

Local data storage and sensitive artifacts

Mobile architecture often fails by caching too much: tokens, PII, or internal API responses in plaintext databases, logs, or crash reports. Define what can be stored locally, for how long, and where. Ensure backups and screenshots don’t leak sensitive screens.

  • Sensitive data is stored only in platform-provided secure storage (Keychain/Keystore) when needed.
  • App avoids writing sensitive data to logs; crash reporting scrubs PII and secrets.
  • Local databases use encryption where appropriate and are protected by OS-level access controls.
  • Backup policies are set to exclude sensitive files from cloud backups when required.
  • Screens that display sensitive data opt out of screenshots/recents thumbnails where applicable.

App integrity signals and abuse resistance

While you cannot fully prevent tampering, you can raise the cost and improve detection. Architecture should define which integrity signals you collect (device attestation, app signing state, debug flags) and how you use them: never as a single point of failure, but as inputs to risk scoring and step-up controls.

  • Device/app attestation is integrated for high-risk actions (payments, account recovery, admin functions).
  • Root/jailbreak and debugger signals are collected (with privacy considerations) and used for risk scoring.
  • Rate limiting and anomaly detection are server-side; the app does not “self-police.”
  • Deep links and app links validate parameters and enforce allowlists to prevent injection and phishing flows.

Step-by-step: safe deep link handling

  • Define a single deep link router with a strict allowlist of paths and parameter schemas.
  • Reject unknown parameters; do not pass raw deep link URLs into webviews or browsers without validation.
  • For links that trigger sensitive actions, require re-authentication or step-up verification.
  • Log deep link activations with anonymized context to detect abuse campaigns.
  • Add automated tests for malformed links, missing parameters, and boundary cases.

Backend and service checklist (APIs, workers, data stores)

Service boundaries, authorization, and “confused deputy” prevention

Backend architectures fail when internal services trust each other too much. A service that receives a request from another service should not automatically assume it is authorized to act on behalf of a user. Establish a clear model: which service makes authorization decisions, how identity and intent are conveyed, and how you prevent privilege escalation via internal calls.

  • Each service has an explicit responsibility: policy decision point vs policy enforcement point.
  • Internal calls carry an authenticated service identity and, when acting for a user, a constrained delegation context.
  • Services validate both “who is calling” and “what they are allowed to request,” not just network location.
  • Admin and backoffice operations are isolated from user-facing paths and require stronger controls.

API design checks: consistency, idempotency, and safe error handling

API architecture should make secure behavior the default. Consistent patterns reduce mistakes: how you paginate, how you handle retries, how you represent resource ownership, and how you return errors. Error messages and status codes should help clients without leaking internals.

  • Idempotency is supported for operations that may be retried (payments, provisioning, invitations).
  • Resource identifiers are opaque; avoid exposing sequential IDs when it increases enumeration risk.
  • Errors are normalized; internal stack traces and dependency details are never returned to clients.
  • Request size limits and timeouts are set at the edge and per service.
  • Rate limiting exists per user, per IP, and per token/client where applicable.

Data access layer: least privilege and blast-radius control

Backends often use a single database user with broad permissions, which turns any injection or SSRF-like pivot into a full data breach. Architecture should enforce least privilege at the data layer and reduce blast radius through segmentation and scoped credentials.

  • Separate database roles for read vs write; separate roles per service when feasible.
  • Row-level security or ownership checks are enforced consistently (in queries, views, or service logic).
  • Production data access is gated (break-glass, approvals, just-in-time access) and audited.
  • Backups are protected and access-controlled; restore procedures are tested.

Asynchronous processing and queues

Queues and event buses introduce new attack surfaces: message spoofing, replay, poison messages, and privilege confusion. Architecture should define message schemas, validation, and dead-letter handling, and ensure that consumers do not trust message content blindly.

  • Messages are validated against schemas; unknown fields are rejected or ignored safely.
  • Producers and consumers authenticate to the broker; topics/queues have strict ACLs.
  • Poison message handling exists (dead-letter queues, retry limits, alerting).
  • Consumers are idempotent; duplicate delivery does not cause double effects.

Step-by-step: hardening a new microservice before first production traffic

  • Define the service’s public contract (OpenAPI/gRPC proto) and generate validation middleware.
  • Create a minimal IAM role for the service; grant only required permissions to dependencies.
  • Set resource limits (CPU/memory), timeouts, and circuit breakers for outbound calls.
  • Add structured logging with request IDs and audit events for sensitive operations.
  • Enable automated scans: dependency scanning, container scanning, IaC policy checks.
  • Deploy behind an API gateway or ingress with rate limits and request size limits.
  • Run a pre-prod abuse test: fuzz inputs, simulate retries, and send malformed messages/events.

Infrastructure and deployment checklist (where architecture meets reality)

Network exposure and segmentation

“It’s internal” is not a control. Assume internal networks are reachable by compromised workloads. Segment by function, restrict east-west traffic, and minimize public exposure. Prefer private connectivity to managed services and restrict egress to reduce data exfiltration paths.

  • Only required services are internet-facing; all others are private by default.
  • Security groups/firewalls are deny-by-default; inbound rules are minimal and reviewed.
  • Egress is controlled for sensitive workloads (allowlist destinations, DNS controls).
  • Metadata service protections are enabled (IMDSv2 or equivalent) to reduce credential theft.

Runtime hardening: containers, VMs, and serverless

Runtime posture is a core part of architecture. Verify that workloads run with minimal privileges, that images are minimal and patched, and that runtime policies prevent common escapes. For serverless, verify permissions and event sources are tightly scoped.

  • Containers run as non-root; read-only filesystem where possible; capabilities are dropped.
  • Images are minimal, scanned, and rebuilt regularly; no package managers in production images unless needed.
  • Serverless functions have least-privilege IAM; environment variables do not contain secrets unless sourced securely.
  • Runtime security monitoring exists (unexpected outbound connections, privilege escalations).

Configuration drift and policy enforcement

Even well-designed systems degrade when manual changes slip in. Use policy-as-code to enforce baseline controls: encryption settings, public access blocks, logging enabled, and approved instance types. The checklist should require that drift is detectable and remediable.

  • IaC is the source of truth; drift detection runs continuously.
  • Policies prevent public buckets, overly permissive security groups, and disabled logging.
  • Changes require review; break-glass changes are time-limited and audited.

Checklist artifacts you should standardize

Evidence pack for each release

To make security verifiable, standardize an “evidence pack” attached to each release or deployment. This is a lightweight bundle of links and outputs that proves the checklist items were met. It also accelerates incident response because you can quickly see what changed and what controls were in place.

  • Links to CI results: tests, scans, linting, policy checks.
  • SBOM and artifact digest/signature references.
  • Deployment diff (IaC plan output) and runtime config snapshot.
  • Dashboards: error rates, auth failures, rate limit blocks, WAF events.
  • Change log of security-relevant config (headers, CORS, permissions, network exposure).

Minimal PR checklist (example)

- [ ] New endpoints have schema validation and request size limits
- [ ] Authorization checks are enforced server-side for new actions
- [ ] No new secrets added to code/config; secret store used
- [ ] Logs do not include PII/secrets; sensitive actions emit audit events
- [ ] Third-party dependencies reviewed; versions pinned
- [ ] Infrastructure changes reviewed; no new public exposure without approval
- [ ] Monitoring/alerts updated for new critical paths

Design review checklist (example categories)

For larger changes, use a design review checklist that forces explicit answers. The point is not to produce perfect documents; it is to surface assumptions early.

  • Entry points and trust boundaries: what is exposed, to whom, and under what conditions?
  • Data handling: what is stored, where, for how long, and who can access it?
  • Abuse cases: what happens under high volume, malformed inputs, and partial outages?
  • Operational controls: how do you rotate credentials, revoke access, and respond to incidents?
  • Deployment posture: what changes in networking, IAM, and runtime privileges?

Now answer the exercise about the content:

Which approach best keeps a secure architecture checklist from slowing delivery while still making security verifiable?

You are right! Congratulations, now go to the next page

You missed! Try again.

Delivery stays fast when checklist items become pipeline gates: design-time questions live in design docs, ship-time items are proven by CI/CD checks, and completion requires concrete evidence like tests, configs, or dashboards.

Next chapter

Failure Cases: How Crypto Breaks in Production

Arrow Right Icon
Download the app to earn free Certification and listen to the courses in the background, even with the screen off.