Not possible to override the Host header on Workers requests

I noticed that it’s not possible to override the Host header on requests. After a bit of digging I found that the Host header is forbidden in the Fetch API:

I think I understand why it’s not possible to set a custom Host in the browser, but for Cloudflare Workers it really puts a damper on conditional proxy applications. Is it possible to relax this restriction? I think it would make sense for Cloudflare Workers.

1 Like

Hi @dan42,

fetch() ignores your setting for the Host header because it initializes the Host header based on the request URL – which you can set! For example, you can do:

fetch("https://www.example.com")

Your worker is free to fetch any URL accessible from the public internet.

If you want to rewrite the URL of your incoming request to go to a different host, you could do something like:

addEventListener("fetch", event => {
  let newUrl = new URL(event.request.url);
  newUrl.hostname = "www.example.com";
  event.respondWith(fetch(newUrl, {
    method: event.request.method,
    headers: event.request.headers
  }));
});

(Sorry that that’s a bit verbose. I’m working with the spec authors to see if we can make it simpler.)

Does that solve your problem, or have I misunderstood?

2 Likes

Hi @dan42,

It occurred to me that you might be trying to set up a request that is routed to an IP address based on one hostname, but reports a different hostname in the Host header. This might make sense for example to reroute some requests to a test server that is configured exactly the same as the original server, so expects the same Host header.

Unfortunately, we can’t allow you to specify a Host header that is inconsistent with the routing for security reasons: Many Cloudflare customers protect their origin by whitelisting Cloudflare’s IP address, using authenticated origin pulls, or other ways, and they rely on the Host header to prove that Cloudflare executed the security settings for their site.

However, now that I think of it, the attack scenario I’m thinking requires the attacker to override a Host header to specify the victim’s zone. I believe we could safely allow you to override the Host header as long as the overridden value identifies a zone you control. Or, a different way of thinking about this is, we could allow you to override your origin’s DNS configuration for a single request. We will look into this.

2 Likes

Hi @KentonVarda,

Yes, that’s what I meant; route to an IP based on one hostname but use a different Host header. I never imagined it could be an attack vector but now that you explain it I can see it indeed.

To give you some context, what I’m trying to do is similar to the stackoverflow question I linked above. Request arrives to www.animenewsnetwork.com and based on some routing logic, either send it to the origin server or to wwwezo.animenewsnetwork.com which is an additional reverse proxy which then forwards the request to the origin (and performs some transformations on the response; see ezoic.com for details; actually they’re a Cloudflare partner I believe). But for that additional reverse proxy step I would like the Host header to remain “www.animenewsnetwork.com”.

Hi @dan42,

Thanks for the feedback, and apologies for misunderstanding at first. I’m looking into implementing an “origin DNS override” feature in the next few weeks.

Hi @KentonVarda, may I ask for an update on this feature? I’d like to know if you’re still planning to implement it or not. Thanks.

Hi @dan42,

Oops, this feature was added a couple weeks ago but I forgot to update the thread. It’s documented here:

https://developers.cloudflare.com/workers/reference/Cloudflare-features/#resolve-override

1 Like

Awesome! Thanks :slight_smile:

Hi @KentonVarda thanks for adding resolveOverride. Could you please explain how workers will work with the Page rules.

  1. Do they happen to work before Page rules are applied or after?
  2. How resolveOverride will work in combination with a Host Header Override page rule?

Many thanks.

Hi @rustem.suniev,

Whether a page rule applies before or after workers depends on what features it is modifying. In general, “security features” run “before” workers (meaning they run on original incoming requests) whereas most other features run “after” (on subrequests, aka fetch()es).

Combining cf.resolveOverride with a “Host Header Override” page rule would have the same effect as combining a “Resolve Override” page rule with a “Host Header Override” page rule. To be honest, I don’t know what that effect is – these features predate Workers and aren’t my focus area. If you are an enterprise customer, I recommend asking your Solutions Engineer about it. If you aren’t an enterprise customer, then you won’t be able to use “Host Header Override” due to the security concerns, but you can use cf.resolveOverride.

2 Likes

2 posts were split to a new topic: Questions regarding Worker proxying

If you know beforehand the set of IPs to conditionally forward to, you could set them up as proxy domains in Cloudflare’s DNS then use fetch() to forward requests to them.

/*
 * DNS
 * Type      Name     Content     TTL     Proxy status
 * CNAME     a        1.2.3.4     Auto    Proxied
 * CNAME     b        2.3.4.5     Auto    Proxied
 * CNAME     c        3.4.5.6     Auto    Proxied
 */
async function proxy(request) {
  const url = new URL(request.url)

  if (/^a\//.test(url.pathname)) {
    url.hostname = 'a.example.com'
  } else if (/^b\//.test(url.pathname)) {
    url.hostname = 'b.example.com'
  } else {
    url.hostname = 'c.example.com'
  }

  return fetch(url, request)
}