Ask
29
@appsec_amara ·

How do I make sure only my own front end can call my API, when the page has no login?

I pay per request for a third-party service. My site calls it from a public page with no authentication, and I proxy the request through my own backend so the paid key is never in the browser.

I have also restricted the endpoint to my own origin. That stops it being called from another website in a browser.

What it does not stop is somebody opening the network tab, copying the request and replaying it from a script. Everything I add seems to be visible to the client and therefore copyable. Is there a way to actually solve this, or am I asking for something impossible?

5 answers Share
Report

Answering anonymously — a moderator will review it first.

  • @threat_model_thea · 2h ago

    You are asking for something impossible, and it is worth being precise about why, because the precise version tells you what to do instead.

    Anything your client possesses, the user possesses. A secret in JavaScript is readable. A signed token issued to an anonymous visitor can be requested by anyone. Even in a compiled mobile app the same holds — it is harder, not different. There is no arrangement in which an anonymous client proves it is "the real client", because there is nothing about it that an attacker cannot also have.

    The origin restriction you added is worth understanding correctly too: it is a browser policy. It stops another website's page from reading your responses. It does nothing about a script, a command line tool, or anything that is not a browser obeying rules voluntarily.

    So drop the goal of authentication and pick up the goal of cost control. That one is achievable.

    30
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @appsec_amara · 2d ago

    The practical toolkit, in the order I would apply it:

    Rate limit aggressively, per IP and globally. A public page has a predictable usage shape. Cap it there. This alone bounds your bill, which is the actual thing you are protecting.

    Cache. If several users can get the same answer, the third-party service should be called once. In many cases this cuts paid calls by a factor of ten or more and simultaneously makes replay pointless, because the replay is served from your cache.

    Set a hard spend ceiling with the provider, if they offer one. This is the only control that is guaranteed to work regardless of what anyone does.

    Add friction proportional to abuse. A challenge for visitors who exceed a threshold, rather than for everybody. It does not stop a determined attacker; it removes the casual ones and buys you time.

    Log and alert. You want to know within minutes, not at the end of the billing period.

    27
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @crypto_curious_can · 17h ago

    One more structural option worth considering before the mitigations: change what you expose.

    Right now your proxy is essentially a free version of the paid service. Anyone who finds it gets exactly what you pay for. That is the strongest possible incentive to abuse it.

    If you can narrow the proxy — restrict which queries it will forward, transform the response so it is only useful in your context, limit parameters to a fixed set — then the endpoint stops being a general-purpose free tier for someone else's product. An attacker copying it gets something much less valuable, and the incentive largely evaporates.

    That is usually more effective than any amount of request signing, because it attacks the motive rather than the mechanism.

    21
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
  • @blue_team_bora · 21h ago · 2 replies

    Worth saying plainly since it is the elephant in the thread: if the data behind the paid API is valuable enough to be worth protecting properly, put it behind a login.

    Authentication is the thing that actually answers "who is calling". Everything else in this thread is damage limitation for the case where you have decided the page must be public. That is often the right decision for reach and conversion reasons — just make it knowingly, rather than trying to get authentication's guarantees without authentication.

    14
    Share
    Reply

    Answering anonymously — a moderator will review it first.

    Report
    • @appsec_amara · 2h ago

      "Stop trying to authenticate, start controlling cost" reframed the whole problem for me. Caching alone would have removed most of what I was worried about.

      9
      Share
      Reply

      Answering anonymously — a moderator will review it first.

      Report