133 lines
4.2 KiB
Markdown
133 lines
4.2 KiB
Markdown
# Attachments
|
|
|
|
## Goals
|
|
|
|
- Preserve school and project files.
|
|
- Avoid filename/path vulnerabilities.
|
|
- Deduplicate identical content.
|
|
- Maintain authorization and provenance.
|
|
- Detect corruption.
|
|
- Never execute uploaded content.
|
|
|
|
## Storage model
|
|
|
|
Physical blobs are addressed by lowercase SHA-256:
|
|
|
|
```text
|
|
/var/lib/knowledge-hub/attachments/ab/cd/<full-sha256>
|
|
```
|
|
|
|
The physical path never contains the user's filename. A logical attachment reference
|
|
stores the original display filename and metadata in PostgreSQL.
|
|
|
|
Temporary uploads use a separate same-filesystem quarantine directory so a validated file
|
|
can be atomically moved.
|
|
|
|
## Upload pipeline
|
|
|
|
1. Authenticate and authorize.
|
|
2. Enforce request and streaming limits.
|
|
3. Sanitize display filename; reject path separators/control characters.
|
|
4. Stream once to quarantine while calculating SHA-256.
|
|
5. Verify actual byte length.
|
|
6. Detect known signatures.
|
|
7. Compare declared type, extension and detected type.
|
|
8. Apply policy:
|
|
- safe raster image: eligible for inline preview;
|
|
- PDF/Office/text/archive/config: download by default;
|
|
- HTML/SVG/script/executable: download-only or reject according to policy;
|
|
- unknown: `application/octet-stream`, download-only.
|
|
9. Atomically commit blob and logical reference.
|
|
10. Generate preview asynchronously where supported.
|
|
11. Remove quarantine data on every failure/cancellation.
|
|
|
|
Default maximum: 100 MiB per file, configurable by administrator. The reverse proxy,
|
|
Kestrel and application limits must agree.
|
|
|
|
## Supported initial categories
|
|
|
|
- PNG, JPEG, GIF, WebP;
|
|
- PDF;
|
|
- plain text and common configuration files;
|
|
- Office documents;
|
|
- common archives as opaque downloads;
|
|
- other opaque files by administrator policy.
|
|
|
|
SVG is not rendered inline in v1. Archives are not extracted as ordinary attachments.
|
|
|
|
## Serving
|
|
|
|
Every content request re-authorizes the logical reference.
|
|
|
|
Headers:
|
|
|
|
- `X-Content-Type-Options: nosniff`;
|
|
- safe `Content-Disposition`;
|
|
- bounded cache policy for private content;
|
|
- CSP/sandbox where inline documents are later enabled;
|
|
- no user-controlled response headers.
|
|
|
|
Inline rendering is initially restricted to known safe raster images. Range requests may
|
|
be added for large downloads with authorization tests.
|
|
|
|
## Deduplication
|
|
|
|
Two logical references may point to one blob.
|
|
|
|
- Deduplication is global inside the installation storage, but authorization always uses
|
|
the logical reference.
|
|
- A caller cannot discover whether a matching private blob already exists.
|
|
- Content hash is not sufficient permission to retrieve.
|
|
- Concurrent uploads with the same SHA-256 serialize the blob lookup, atomic commit
|
|
and database insert. Every upload receives its own logical reference while exactly
|
|
one physical blob is retained; uploads with different hashes remain concurrent.
|
|
- Blob cleanup occurs only when no active or retained reference remains.
|
|
- Reference counts are derived or transactionally maintained and periodically verified.
|
|
|
|
## Image metadata
|
|
|
|
Logical references may store:
|
|
|
|
- alt text;
|
|
- caption;
|
|
- width/height;
|
|
- rotation-normalized preview;
|
|
- uploader and upload time.
|
|
|
|
Strip unnecessary metadata from generated previews. Preserve the original bytes as the
|
|
blob unless policy explicitly rejects them.
|
|
|
|
## Integrity
|
|
|
|
- New blobs are verified after atomic move.
|
|
- Scheduled sampling/full scan recalculates hashes.
|
|
- Missing/corrupt blobs mark references degraded and alert administrators.
|
|
- Backups include a blob manifest and hashes.
|
|
- Restore validates before enabling normal write traffic.
|
|
|
|
## Deletion
|
|
|
|
Deleting an attachment use/reference is logical first. Retention protects accidental
|
|
deletion. Orphan physical blobs are cleaned in a background job after the configured
|
|
window and a final transactional reference check.
|
|
|
|
## Security tests
|
|
|
|
Include:
|
|
|
|
- double extensions;
|
|
- path traversal names;
|
|
- null/control characters;
|
|
- oversized/chunked uploads;
|
|
- declared/detected MIME mismatch;
|
|
- HTML/SVG stored XSS;
|
|
- polyglot samples where feasible;
|
|
- executable/script files;
|
|
- authorization ID substitution;
|
|
- interrupted upload cleanup;
|
|
- duplicate content;
|
|
- concurrent duplicate uploads;
|
|
- malicious archive names without extraction;
|
|
- race between deletion and download;
|
|
- corruption detection.
|