Skip to content

feat: in-code defense-in-depth security middleware (body cap, request timeout, tower-governor) #32

@proofmancer

Description

@proofmancer

What

Add tower middleware to the axum router so the api defends itself even if Cloudflare is bypassed or misconfigured:

  1. RequestBodyLimitLayer on POST /v1/drip -- cap at 16 KB. Default axum is generous; a tiny JSON body is all this endpoint ever sees.
  2. TimeoutLayer at 30s per request. Prevents slow-loris from holding handlers open.
  3. tower-governor (or homegrown IP-bucket) for per-IP rate limit: 10 req/min global, 3 req/min on POST /v1/drip. Belt-and-suspenders with Cloudflare's rate limits.
  4. HTTP security headers: X-Content-Type-Options: nosniff, Referrer-Policy: same-origin, no Server: header, etc. Cheap with tower-http SetResponseHeader.
  5. Structured drip log -- log each /v1/drip with target_address, client_ip, tx_hash (or rejection reason) at INFO. Currently we log "drip signer loaded" + per-drip latency but not the per-call audit trail.

Why

Cloudflare's WAF + rate limit handles ~95% of attacks at the edge, but:

  • A bug in Cloudflare config could expose the origin (Railway pubic URL ligate-api-production.up.railway.app)
  • Future infra changes (e.g., adding direct VPC access for explorer) might bypass the edge
  • An in-code limit is a backstop the platform layer can't accidentally drop

Test plan

  • Add layers in crates/api/src/main.rs (between Router::new() and axum::serve())
  • Unit test: send 11 POSTs to /v1/drip in 60s; expect first 10 to 200/429-from-rate-limit, 11th to 429
  • Verify drip log format with a real drip (post Gate D)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions