DEV Community

Serguey Asael Shinder
Serguey Asael Shinder

Posted on

Your Answer Is Private Because One Header Says So

A browser will let any page
send a request to your API.

It has always allowed that.

What it will not allow
is that page reading the answer,
unless your response says it may.

That single rule
is most of what stands between
your signed-in customer
and every other tab
they have open.

Now watch how it gets given away.

Somebody is fixing a preview build.
The front end is on one host,
the API on another,
and nothing works.

The quickest thing that works
is to echo back
whatever origin arrived
in the request,
and add the header
that permits credentials.

Both lines read like plumbing.

Neither of them feels like
a decision about who
may read a customer's account.

What has been written is this.

Any site, anywhere,
may make a request
that carries your customer's cookie,
and may read every byte
that comes back.

No password is needed.
No token has to leak.

It needs the customer
to have your tab open
and to load one other page.

A forum post. An advert.
A link in an email
they were expecting.

The request is authenticated
because the browser attaches
what browsers attach,
and the response is readable
because you said so,
in writing,
on every reply.

Your logs will show
an ordinary two hundred,
from a real session,
at a plausible hour,
from an address
that belongs to the customer.

There is nothing there to detect.

So treat that header
as a list of names.

Write the origins out.
Your own hosts, spelled in full,
a short list, in code,
that somebody has to edit
in a pull request
where the question gets asked
out loud.

Never the value that came in.

And keep the two decisions apart.
Allowing an origin is small.
Allowing an origin
with credentials attached
is handing over a session.

Go and read the headers
your own service returns
right now.

Ask what the list names.

If it names whoever asked,
you have a door propped open
in production,
and the browser was the only thing
that had been holding it.

– Serguey Asael Shinder

Top comments (0)