Skip to content

[High] Relay /subscribe and /n/<id> have no auth, rate limit, or body size cap #6

@json9512

Description

@json9512

What

`server/sshido-relay/deploy-cloud-run.sh:40` deploys Cloud Run with `--allow-unauthenticated`, and `server/sshido-relay/main.go:168-277` implements both POST endpoints with:

  • No per-IP throttling
  • No per-token throttling
  • No `http.MaxBytesReader` on the request body
  • Bare `json.NewDecoder(r.Body).Decode(&req)` (lines 174, 221)

There is also no notify-URL rotation: `UpsertByDeviceToken` returns the same subscriber id forever for the same APNs token.

Concrete attacks

  1. Subscriber-spam: anyone POSTs random device tokens to `/subscribe` → unbounded Firestore writes → billing exposure on a free-tier Cloud Run.
  2. Notify-URL pwning: any leaked Notify URL (screenshot of Settings, terminal scrollback, casual share with a coworker) lets the holder push unlimited high-priority alerts to the device. Each one is a Cloud Run invocation + Firestore write that the operator pays for. The user cannot rotate the URL without un/reinstalling to get a new APNs token.
  3. Memory pressure: the 256Mi Cloud Run instance can be force-fed huge JSON bodies until OOM.

Suggested fix

  • Wrap every handler with `http.MaxBytesReader(w, r.Body, 41024)` (notify) / `11024` (subscribe).
  • In-process token-bucket per subscriber id and per source IP, e.g. `golang.org/x/time/rate`. Even 5 rps with burst 10 kills the abuse case without affecting real users.
  • Add a notify-URL rotation: `POST /rotate` (auth: includes the current device token) returns a new id and invalidates the old one. Wire it to a "Rotate notify URL" button in Settings.
  • Set per-day push count limit per subscriber; over the cap, reply 429 and stop hitting APNs.

Acceptance

  • Bench shows abuse paths return 429 instead of 200.
  • Notify-URL rotation works end-to-end in the iOS app.
  • Body size cap is unit-tested with a 1 MiB payload.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions