Get the request host in the worker

Hi, I am looking for a solution to setting the CORS Access-Control-Allow-Origin header value dynamically based on from where the worker is being called. I have two origins I want to allow calling the worker, but not others. Therefore I can’t use * for the header value. Another reason I can’t use it is that using * would prevent me from using credentials: ‘include’ on the fetch which is also something I need. I figured this might be easy by just pulling the host from the request headers and setting the ACAO header value to that in the response headers, however, the host in the request headers always has the value of the worker host, not the peer host. Why is that? And is there a way to get the host value of the connection peer?

Example:

Is this possible?

Can you post your code?

request.headers.get("Host") should actually return the value you are after. Equally, request.url.

addEventListener('fetch', event => event.respondWith(handleRequest(event.request)));

async function handleRequest(request) {
  let result = 'url: ' + request.url + '\n';
  for (const header of request.headers) {
    result += 'header: ' + header + '\n';
  }

  return new Response(result);
}

Run using fetch('https://test.tomashubelbauer.workers.dev/').then(r => r.text()).then(console.log)

For me it gives:

url: https://test.tomashubelbauer.workers.dev/
header: accept,*/*
header: accept-encoding,gzip
header: accept-language,en-US,en;q=0.5
header: cache-control,no-cache
header: cf-connecting-ip,{redacted}
header: cf-ipcountry,CZ
header: cf-ray,{redacted}
header: cf-visitor,{"scheme":"https"}
header: connection,Keep-Alive
header: dnt,1
header: host,test.tomashubelbauer.workers.dev
header: origin,null
header: pragma,no-cache
header: user-agent,Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0
header: x-forwarded-proto,https
header: x-real-ip,{redacted}

As you can see, the host is of the worker.

I don’t think request.url should be what I’m after. The request is from the client to the worker, so the request is for the worker at some URL… Maybe the same logic applies to the host header, IDK, but I hope there is a way to get the host name of the peer from the perspective of the worker - the website making the request against the worker.

You seeem to be executing the worker in the context of the playground, in which case that is the URL (your own fetch call refers to that URL). You will need to execute it in the context of your site instead, in which case you will get the applicable values.

This was ran in a new, blank tab in Firefox, not the worker playground (I don’t use it). Try running it in your dev tools, I believe you will see the same results as me.

You sent the request to https://test.tomashubelbauer.workers.dev/, hence that URL will show up as it is the URL in question.

Again, you need to map that worker to your site(s) and call it in that context instead. You cannot expect to get a different URL if you call that URL.

To visualise this even better -> https://cloudflareworkers.com/#491b503cc13707a9cb0a01c0ce7acc3b:https://tutorial.cloudflareworkers.com

1 Like

I don’t use any other Cloudflare products other than Workers, so I have nowhere to map it to. I am calling the worker from a site served using a static file server. Since I am calling the worker directly, is there a way to find the caller? To extend my example above:

Is this possible? I see now that the request host header in this case is correct, but I am interested in any solution that helps identify the caller.

Not in the way you intended. Where should it take that value from? You cannot expect to request a certain URL and then use that URL to set another value, however with a third party value. I am sorry, but the approach simply cant work.

You could probably pass some additional parameter to your request where you manually specify the value you want added.

Otherwise simply map the worker to your domains as I explained earlier.

Understood. I see now that the request host value is correct, what I had in mind initially is more akin to say a referrer header, which is not applicable in this case. I don’t think there is a good solution then, because I can’t even use the connection peer IP as the request is not coming from another server, but the client browser running the site. This being the case, I will look into providing an additional X-header on the caller side and whitelisting the values of that. To reiterate, I don’t use any (including domains) other products from Cloudflare other than Workers, so mapping workers to domains is not possible.

Alright, in this case you naturally cant map it. An additional header will be your only chance then (the referrer is just yet another header as well).

Just make sure you sanitise and verify that value, as anybody else could otherwise pass their own values.

1 Like

Yes, by whitelisting the value to the only two origins I want to allow, I will strip an attacker of the option to enable CORS for their own site and the ACAO header pointed at either of my sites won’t do them any good, I agree with you. Thanks for your support, I was hoping there was a way to uniquely identifying the clients out of the box, but I will use a custom header and it will work just as well.

Also thanks for the cool tip with cloudflareworkers.com, that’s a useful playground to have without having to spin up one’s own test worker.

I found the answer after all - it’s the Origin header! I was mistaking it for Host which led me to a very confused search, but I knew there was a way to get this information out of the box. With reading the Origin and setting it for the ACAO header (after checking the whitelist), it all works how I wanted it to.