Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hostname of request object in middleware is always 'localhost' #37536

Closed
1 task done
bb-in-hoodie opened this issue Jun 8, 2022 · 10 comments
Closed
1 task done

Hostname of request object in middleware is always 'localhost' #37536

bb-in-hoodie opened this issue Jun 8, 2022 · 10 comments
Labels
Middleware Related to Next.js Middleware

Comments

@bb-in-hoodie
Copy link

Verify canary release

  • I verified that the issue exists in Next.js canary release

Provide environment information

    Operating System:
      Platform: darwin
      Arch: x64
      Version: Darwin Kernel Version 21.5.0: Tue Apr 26 21:08:22 PDT 2022; root:xnu-8020.121.3~4/RELEASE_X86_64
    Binaries:
      Node: 14.19.1
      npm: 8.12.1
      Yarn: 1.22.18
      pnpm: N/A
    Relevant packages:
      next: 12.1.7-canary.31
      react: 18.1.0
      react-dom: 18.1.0

What browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

Describe the Bug

image

(I edited local /etc/hosts file to reproduce the issue, but the same issue happens even when I deploy an app and connect a domain to that.)

Whatever domain is being used, request object, which is an input of a middleware function, always has "localhost" as its hostname.

I use middleware to store all the access logs to an ES storage. Because request.url or request.nextUrl always has '"localhost"' as its hostname, I cannot distinguish stage.something.com from something.com or dev.something.com.

Expected Behavior

It should has the actual URL information. (in the example above, hostname should be test.domain.ai).

To Reproduce

  1. npx create-next-app@latest --typescript
  2. add middleware function
    /* eslint-disable @next/next/no-server-import-in-page */
    import { NextResponse } from "next/server";
    import type { NextMiddleware } from "next/server";
    
    const middleware: NextMiddleware = (request) => {
      const response = NextResponse.next();
    
      const { url, nextUrl } = request;
      const { host, hostname } = nextUrl;
      console.log({ url, host, hostname });
    
      return response;
    };
    
    export default middleware;
  3. edit local /etc/hosts
    127.0.0.1 test.domain.ai
    
  4. access test.domain.ai from any web browser
@bb-in-hoodie bb-in-hoodie added the bug Issue was opened via the bug report template. label Jun 8, 2022
@balazsorban44 balazsorban44 added the Middleware Related to Next.js Middleware label Jun 9, 2022
@hannesl
Copy link

hannesl commented Jun 13, 2022

From what I can tell this was introduced in 12.0.8. With 12.0.7 I get the real hostname in request.nextUrl.

@balazsorban44
Copy link
Member

balazsorban44 commented Jun 13, 2022

So both hostname and port can be changed by passing the flags to the next start and/or next dev CLI commands.

Example: next dev --hostname domain.com --port 8000

If you configure /etc/host as well, you should be able to access the server at http://domain.com:8000 for example, and Middleware would pick this up as well.

The relevant documentation is here, but it could be improved:
https://nextjs.org/docs/api-reference/cli

@balazsorban44 balazsorban44 added area: documentation and removed bug Issue was opened via the bug report template. labels Jun 13, 2022
@hannesl
Copy link

hannesl commented Jun 14, 2022

Thanks @balazsorban44 but for my use case I depend on being able to get the actual hostname that the request uses. It's often the case that a website can be reached through more than one hostname, and for me that information is important.

My use case aside, I think most people would expect a request object to reflect the actual request URL, not a URL that is constructed from the application config.

@bb-in-hoodie
Copy link
Author

bb-in-hoodie commented Jun 15, 2022

agree on what @hannesl said.

for me, inserting hostname via env var doesn't feel far from manually choosing which domain would be stored in an access log with an if statement inside of our code.

as hannesl said, sometimes we don't even know which domain would be used because there could be multiple domains connected to a single server, or you may change the domain someday, and what so ever. we don't configure domains inside of our code neither inside of our docker container, it's usually done outside of our application level. so env var trick might be a workaround for now, but definitely not a solution for this issue.

@balazsorban44
Copy link
Member

The problem is that the only way to detect the host is through the request's headers, which could be forged and thus makes it unreliable.

@bb-in-hoodie
Copy link
Author

well.. I think even a fake hostname is still way better than "localhost".
It's developers' choice whether to trust or not to trust a hostname they've received.

@balazsorban44
Copy link
Member

balazsorban44 commented Jun 15, 2022

⚠️ Note: the following should be done if you are absolutely positive that you can trust your incoming request's headers, otherwise doing this can be very unsafe:

The request headers are actually not overwritten like url and nextUrl, so you can write a simple wrapper for your middleware that will keep nextUrl and url updated:

function withHostFromHeaders(middleware) {
  return (...args) => {
    let { nextUrl, headers, url } = args[0]
    nextUrl.host = headers.get("Host") ?? nextUrl.host
    url = nextUrl.href
    return middleware(...args)
  }
}

export default withHostFromHeaders((req) => {
  const { url, nextUrl } = req
  console.log({ nextUrl, url })
})

@hannesl
Copy link

hannesl commented Jun 16, 2022

Thanks @balazsorban44 ! Just using req.headers.get("Host") in a standard middleware implementation works as well. Didn't think of that. So that solves my issue, even thought I still found the default behaviour strange.

@balazsorban44
Copy link
Member

Understandable, but this is to increase security when hosting outside of Vercel, as you may understand. Closing with the above suggestion #37536 (comment).

Again, use it with care, only if you trust your proxy.

@github-actions
Copy link
Contributor

This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 21, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Middleware Related to Next.js Middleware
Projects
None yet
Development

No branches or pull requests

4 participants