[VS-NfD] Add SHA-256 integrity hashes for attachments #199

Closed
opened 2026-07-30 01:43:35 +02:00 by fable-5 · 1 comment
Collaborator

Plan reference: 20-massnahmenplan.md -> Phase 2 (pulled from roadmap)
ADR: n/a
Effort: M (2–3 AT)
Depends on:

Context

Integrity is the one security base function §52 VSA leaves to the
application in the sense of detecting manipulation of its own payloads —
a checksum is not a protection mechanism the platform can supply, because
only the application knows what the file should be. Side benefits:
orphan sweep, dedup, backup verification.

Current state

  • The Attachment model (apps/api/prisma/schema.prisma:530–559) carries
    no checksum column; the only hashes in the schema are credential/token
    hashes (token_hash, session id, credential).
  • Files are written by apps/api/src/files/files.service.ts.

Acceptance criteria

  • A sha256 column is added by migration; the hash is computed during
    upload (streaming, not by re-reading the file) and stored.
  • Download verifies the hash and fails closed with a distinguishable
    error when it does not match; the mismatch is audited.
  • A backfill migration or job hashes existing attachments and reports
    progress; unreadable files are reported, not silently skipped.
  • Tests: upload stores the correct hash; tampering with the file on
    disk makes download fail; backfill is idempotent.
  • docs/architecture/security.md §"Content & upload security" and #229
    document the behaviour, including what an operator does when
    verification fails.

Out of scope

Signatures (needs a signing identity — see ADR 0025), content
encryption (ADR 0019), and dedup by hash.

**Plan reference:** `20-massnahmenplan.md` -> Phase 2 (pulled from roadmap) **ADR:** n/a **Effort:** M (2–3 AT) **Depends on:** — ## Context Integrity is the one security base function §52 VSA leaves to the application in the sense of *detecting* manipulation of its own payloads — a checksum is not a protection mechanism the platform can supply, because only the application knows what the file should be. Side benefits: orphan sweep, dedup, backup verification. ## Current state - The `Attachment` model (`apps/api/prisma/schema.prisma:530–559`) carries no checksum column; the only hashes in the schema are credential/token hashes (`token_hash`, session id, `credential`). - Files are written by `apps/api/src/files/files.service.ts`. ## Acceptance criteria - [ ] A `sha256` column is added by migration; the hash is computed during upload (streaming, not by re-reading the file) and stored. - [ ] Download verifies the hash and fails closed with a distinguishable error when it does not match; the mismatch is audited. - [ ] A backfill migration or job hashes existing attachments and reports progress; unreadable files are reported, not silently skipped. - [ ] Tests: upload stores the correct hash; tampering with the file on disk makes download fail; backfill is idempotent. - [ ] `docs/architecture/security.md` §"Content & upload security" and #229 document the behaviour, including what an operator does when verification fails. ## Out of scope Signatures (needs a signing identity — see ADR 0025), content encryption (ADR 0019), and dedup by hash.
fable-5 added this to the M25 — VS-NfD: hardening & supply chain milestone 2026-07-30 01:43:35 +02:00
fable-5 added the
vs-nfd
effort:M
area:storage
labels 2026-07-30 01:43:35 +02:00
Author
Collaborator

Implemented in PR #259 (commit 74970f6, CI run 522 green, fast-forward merged per Stefan's standing go-ahead for the M25 block).

Evidence against the acceptance criteria:

  • sha256 column added by migration 20260731090000_attachment_sha256; upload computes the hash from the in-memory buffer being written (streaming in the sense demanded: never re-reads the file from disk).
  • Download verifies BEFORE serving a byte and fails closed with attachment_integrity_failure (HTTP 500); the mismatch is audited as file.integrity_failed with expected+actual hashes. Null-hash rows (pre-backfill) are served unverified - the pre-#199 status quo.
  • Backfill: bounded, idempotent batch riding the existing nightly orphan-file-sweep job (no new scheduler job); progress logged per run; unreadable files logged and retried, never silently skipped.
  • Tests (attachment-integrity.e2e.db.test.ts): upload stores the correct hash; on-disk tamper makes download fail closed with the code and the audit row; backfill restores hashes, keeps unreadable rows null, second run idempotent. Full api suite green; migrate deploy verified on a fresh DB.
  • security.md (Content & upload security) documents behaviour and the operator response (restore from backup, re-download, audit entry carries both hashes); deletion-chapter note recorded on #229.

CD verification (migration applies on stages) follows.

Implemented in PR #259 (commit 74970f6, CI run 522 green, fast-forward merged per Stefan's standing go-ahead for the M25 block). Evidence against the acceptance criteria: - sha256 column added by migration 20260731090000_attachment_sha256; upload computes the hash from the in-memory buffer being written (streaming in the sense demanded: never re-reads the file from disk). - Download verifies BEFORE serving a byte and fails closed with attachment_integrity_failure (HTTP 500); the mismatch is audited as file.integrity_failed with expected+actual hashes. Null-hash rows (pre-backfill) are served unverified - the pre-#199 status quo. - Backfill: bounded, idempotent batch riding the existing nightly orphan-file-sweep job (no new scheduler job); progress logged per run; unreadable files logged and retried, never silently skipped. - Tests (attachment-integrity.e2e.db.test.ts): upload stores the correct hash; on-disk tamper makes download fail closed with the code and the audit row; backfill restores hashes, keeps unreadable rows null, second run idempotent. Full api suite green; migrate deploy verified on a fresh DB. - security.md (Content & upload security) documents behaviour and the operator response (restore from backup, re-download, audit entry carries both hashes); deletion-chapter note recorded on #229. CD verification (migration applies on stages) follows.
Sign in to join this conversation.
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: stwaidele/dorfteich#199
No description provided.