GO-180 Trust Center

SECURITY ARCHITECTURE

A control-by-control look at how GO-180 protects veteran data — the encryption, identity, payment, and audit machinery, drawn out in plain English.

TLS 1.2+ / HSTSAES-256-GCMArgon2idTOTP 2FAHMAC-SHA256 audit chainPCI SAQ-A

Defense in depth, by design

Security at GO-180 is layered: transport, identity, data, payments, and an immutable audit trail each stand on their own. Below is exactly how each layer works.

  • Encrypted in transit with TLS 1.2+ and one-year HSTS
  • Documents encrypted at rest with AES-256-GCM
  • Dual JWT identity with instant Redis revocation
  • TOTP two-factor enforced for all administrators
  • Card data never touches our servers (PCI SAQ-A)
  • Tamper-evident, HMAC-chained audit log

The diagrams below mirror the real middleware chain, services, and key-management code that run in production.

Request lifecycle

How a request is handled

Before any request reaches application logic it passes through a defense-in-depth middleware chain. Each stage has one job, and a failure at any stage stops the request.

request-lifecycle.txt
Browser
   |  HTTPS / TLS 1.2+   (HSTS: 1 year, includeSubDomains, preload)
   v
Daphne ASGI server
   |
   v
 [ 1] RequestID .......... tags every request + log line for tracing
 [ 2] Security / HSTS .... forces HTTPS, sets strict security headers
 [ 3] CORS ............... strict origin allow-list (no wildcards)
 [ 4] CSP ................ content-security-policy, frame-ancestors none
 [ 5] CSRF ............... token enforced on any session-auth request
 [ 6] AuthMiddleware ..... verifies USER jwt + Redis blacklist
 [ 7] AdminAuth + TOTP ... verifies ADMIN jwt (separate key) + 2FA gate
 [ 8] SessionTimeout ..... 15-min idle auto-logoff (HIPAA 164.312)
 [ 9] MinimumNecessary ... redacts PHI fields for non-owners
 [10] SubscriptionGate ... 402 unless the account is entitled
   |
   v
View  ->  Serializer (validation)  ->  Service  ->  Django ORM  ->  PostgreSQL
Every request is identified, forced onto HTTPS, origin-checked, authenticated, PHI-redacted, and entitlement-gated before a single row is read from the database.
TLS

ENCRYPTED TRANSPORT

Every byte travels over HTTPS/TLS 1.2+. HSTS is set to one year with subdomain coverage and preload eligibility, so browsers refuse to connect over plain HTTP.

HARDENED HEADERS

A strict Content-Security-Policy, X-Frame-Options DENY, nosniff, and a same-origin referrer policy defend against XSS, clickjacking, and MIME confusion.

RATE LIMITING

Roughly two dozen endpoint-specific throttles cap login, OTP, AI, search, and admin traffic — blunting brute-force, bombing, and cost-abuse attempts.

  • Login 10/min, critical ops 5/min
  • OTP send 3/h, verify 5/h
  • AI chat 30/h, anon 100/h
HIPAA

MINIMUM-NECESSARY PHI

On cross-user reads, middleware automatically redacts protected health and financial fields so staff only ever see the minimum data required.

IDLE AUTO-LOGOFF

Sessions expire after 15 minutes of inactivity, with a client-side warning beforehand — aligned with the HIPAA automatic-logoff safeguard.

ISOLATED ERROR MONITORING

Errors flow to Sentry with personally-identifiable data disabled and conservative sampling, so diagnostics never leak sensitive payloads.

Identity & access

Proving who you are — and revoking it instantly

Authentication separates ordinary users from administrators at the cryptographic level, adds a second factor for privileged accounts, and can revoke access the moment you log out.

authentication-flow.txt
[1] CREDENTIALS
    email + password
       |
       v   Argon2id verify   (login throttle: 10 / min)
[2] BRUTE-FORCE GUARD
    3 failed attempts within 15 min  -->  account locked for 15 min
       | pass
       v
[3] STEP-UP  (admin / super_admin)
    TOTP 6-digit code, RFC 6238  -->  required before tokens are issued
       | pass
       v
[4] TOKEN ISSUE                     signed with HS256 (HMAC-SHA256)
    access  token  -  15 minutes  -  key = JWT_SECRET_KEY  (users)
    refresh token  -   1 hour     -  key = ADMIN_JWT_SECRET_KEY (admins)
       |
       v
[5] EVERY REQUEST
    verify signature  +  check Redis blacklist
       |
       v
[6] REVOCATION
    logout / password change  -->  tokens blacklisted in Redis
    rule:  token_iat <= invalid_before   ==>   token rejected
Credentials are verified with Argon2id, throttled and lockout-protected, optionally stepped-up with TOTP, then exchanged for short-lived signed tokens that can be blacklisted on demand.

DUAL JWT ISOLATION

User and admin tokens are signed with separate secret keys. A stolen user token can never reach an admin route, and vice-versa.

INSTANT REVOCATION

Logout and password changes blacklist tokens in Redis immediately. A same-second cutoff rule rejects any token issued before the revocation point.

2FA

TWO-FACTOR FOR ADMINS

TOTP (RFC 6238) is enforced for every admin and super-admin. Secrets are encrypted at rest and backed by single-use, hashed recovery codes.

BRUTE-FORCE LOCKOUT

Three failed logins inside a 15-minute window lock the account for 15 minutes. Locked and deleted accounts are excluded from re-lock abuse.

ARGON2 PASSWORD HASHING

Passwords are hashed with Argon2id, the memory-hard algorithm recommended by OWASP, with automatic upgrade of any legacy hashes on login.

ROLE-BASED ACCESS

Seven distinct roles gate what each account can see and do, enforced at the view layer rather than trusted from the client.

Data protection

Encryption & key management

Uploaded documents — DD-214s, pay stubs, benefit letters — are encrypted with authenticated AES-256-GCM, with keys derived per-purpose and delivery keys never transmitted in the clear.

document-encryption.txt
UPLOAD
  file  -->  object storage   (TLS in transit, encrypted at rest)
              |
              v   returns a storage URL
ENCRYPT THE URL                          lib/security/encryption.py
  master key:  DOCUMENT_ENCRYPTION_KEY
       |
       v   HKDF-SHA256  ->  derive a per-purpose key
       |                    AAD = "go180:document_url:v1"
       v
  AES-256-GCM( url )
       |   nonce(12B)  ||  ciphertext  ||  auth-tag(16B)
       v
  envelope:   enc:v1:<base64url>
       |
       v
DELIVER
  key is never sent raw -- scrambled with SHA-256(access_token) XOR
       |
       v
  client decrypts in-session;  any tampering flips the GCM tag  -->  rejected
Keys are derived with HKDF-SHA256 from a server-only master secret, additional-authenticated-data binds each ciphertext to its purpose, and GCM authentication tags make tampering detectable.
AEAD

AES-256-GCM

Authenticated encryption protects document URLs and files. The 128-bit tag means any modification is detected and the data is rejected rather than served.

HKDF KEY DERIVATION

Per-purpose keys are derived with HKDF-SHA256 from a single master secret held only in the server environment — never in source control or the database.

VERSIONED + ROTATABLE

A versioned enc:v1: envelope means the scheme can evolve, and rotating the master key transparently invalidates old derived material.

Payments

Billing you can't over-charge or replay

GO-180 never sees your card number. Stripe handles card entry; we only ever process cryptographically verified, de-duplicated webhook events.

stripe-webhook.txt
Stripe  --POST event-->  /api/v1/subscriptions/webhook/
                             |
                             v
[1] VERIFY SIGNATURE      stripe.Webhook.construct_event()
    HMAC-SHA256 over the raw body using STRIPE_WEBHOOK_SECRET
    + timestamp tolerance check (replay protection)
       |  bad signature / stale  -->  400, nothing is processed
       v  ok
[2] IDEMPOTENCY GUARD
    event.id already seen?  -- yes -->  ack 200, do nothing
       | no                             (ProcessedWebhookEvent table
       v                                 + select_for_update row lock)
[3] APPLY
    update subscription  +  record PaymentTransaction (immutable)
       |
       v
[4] ACK 200
    SubscriptionGate now reflects the new entitlement state

card numbers (PAN / CVV) are entered on Stripe's hosted surface --
they never touch GO-180 servers.  PCI-DSS scope = SAQ-A.
Every webhook is signature-verified with HMAC-SHA256, checked for replay, and de-duplicated under a row lock before a single subscription or payment record changes.
PCI SAQ-A

CARD DATA OFF-SERVER

Card numbers are entered on Stripe's hosted surface and tokenized. Our PCI-DSS footprint is the simplest tier, SAQ-A.

SIGNED WEBHOOKS

Each event is verified with HMAC-SHA256 against the Stripe signing secret plus a timestamp tolerance, so forged or replayed events are dropped.

IDEMPOTENT + AUDITED

A processed-event table with row locking prevents double-processing, and every charge or refund writes an immutable PaymentTransaction record.

Accountability

A tamper-evident audit trail

Sensitive actions are written to an append-only audit log whose rows are cryptographically chained, so any attempt to quietly edit or delete history is detectable.

audit-hash-chain.txt
Every sensitive action  (login, PHI read, admin change, data export)
       |
       v
  build row:  actor . action . target . outcome . ip . timestamp
       |
       v   HMAC-SHA256( prev_hash || this_row )    key = AUDIT_INTEGRITY_KEY
       |       (a Postgres advisory lock serializes insert + stamp)
       v
  row[n].hash  --chains-->  row[n+1].prev_hash  -->  row[n+2]  -->  ...
       |
       v
VERIFY
  recompute the chain;  any edited or deleted row breaks the link.
  checkpoint signatures additionally detect tail-deletion.
Each row is HMAC-chained to the one before it under a database advisory lock. Recomputing the chain reveals any altered or removed entry; checkpoint signatures catch tail-deletion.

CATEGORIZED RETENTION

Auth, user-action, admin, and system events are retained on schedules enforced by automated background jobs, from 30 days up to seven years for admin actions.

164.312(b)

PHI ACCESS LOGGED

Reads of protected health information emit a dedicated audit action, supporting the HIPAA audit-controls safeguard.

FORENSIC CORRELATION

A per-request ID threads through every log line and audit row, so an incident can be reconstructed end-to-end.