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

Is there a way to setup CORS origins? Nginx config overwritten by postgrest #2441

Closed
yevon opened this issue Aug 21, 2022 · 13 comments · Fixed by #2986
Closed

Is there a way to setup CORS origins? Nginx config overwritten by postgrest #2441

yevon opened this issue Aug 21, 2022 · 13 comments · Fixed by #2986
Assignees
Labels
difficulty: beginner Pure Haskell task

Comments

@yevon
Copy link
Contributor

yevon commented Aug 21, 2022

I was trying to setup nginx CORS rules for my project in nginx ingress in kubernetes, until I realized a weird behaviour, and it is that postgrest is always adding the "access-control-allow-origin: *" header. Is there a way to completely disable this? or modify this header? As nginx is returning this header when it shoudn't. It would be nice being able to disable this behaviour, or just being able to modify the origins returned by the access-control-allow-origin header.

@steve-chavez
Copy link
Member

Sure, this shouldn't be too hard to customize. The cors logic is on this file:

-- | CORS policy to be used in by Wai Cors middleware
corsPolicy :: Wai.Request -> Maybe Wai.CorsResourcePolicy
corsPolicy req = case lookup "origin" headers of
Just origin ->
Just Wai.CorsResourcePolicy
{ Wai.corsOrigins = Just ([origin], True)
, Wai.corsMethods = ["GET", "POST", "PATCH", "PUT", "DELETE", "OPTIONS"]
, Wai.corsRequestHeaders = "Authorization" : accHeaders
, Wai.corsExposedHeaders = Just
[ "Content-Encoding", "Content-Location", "Content-Range", "Content-Type"
, "Date", "Location", "Server", "Transfer-Encoding", "Range-Unit"]
, Wai.corsMaxAge = Just $ 60*60*24
, Wai.corsVaryOrigin = False
, Wai.corsRequireOrigin = False
, Wai.corsIgnoreFailures = True
}
Nothing -> Nothing
where
headers = Wai.requestHeaders req
accHeaders = case lookup "access-control-request-headers" headers of
Just hdrs -> map (CI.mk . BS.strip) $ BS.split ',' hdrs
-- Impossible case, Middleware.Cors will not evaluate this when
-- the Access-Control-Request-Headers header is not set.
Nothing -> []

@steve-chavez steve-chavez added enhancement a feature, ready for implementation idea Needs of discussion to become an enhancement, not ready for implementation and removed enhancement a feature, ready for implementation labels Aug 23, 2022
@yevon
Copy link
Contributor Author

yevon commented Aug 23, 2022

Ok thanks, I would need this before going to production, as having open cors in an api with authentication might be a high security risk. I didn't found a way to tell nginx proxy to ignore postgrest cors headers yet, and only use those defined in nginx. I might look into this when I have some time, but maybe other can implement this easily.

@wolfgangwalther
Copy link
Member

To do this at the proxy level with nginx, you could just use proxy_hide_header: https://stackoverflow.com/a/56617888

@yevon
Copy link
Contributor Author

yevon commented Aug 28, 2022

To do this at the proxy level with nginx, you could just use proxy_hide_header: https://stackoverflow.com/a/56617888

Amazing! I will try this thanks.

@yevon
Copy link
Contributor Author

yevon commented Aug 28, 2022

I tried:

nginx.org/proxy-hide-headers: "Access-Control-Allow-Origin,Access-Control-Allow-Credentials,Access-Control-Allow-Methods,Access-Control-Allow-Headers,Access-Control-Max-Age"

But it doesn't seem to be working, maybe I'm missing something.

@laurenceisla
Copy link
Member

Just to give an example to hide the access-control-allow-origin header using #2441 (comment):

server {

  # ...

  location /api/ {
    default_type  application/json;
    proxy_hide_header Content-Location;
    add_header Content-Location  /api/$upstream_http_content_location;
    proxy_set_header  Connection "";
    proxy_http_version 1.1;
    proxy_pass http://postgrest/;

    # Hides the header
    proxy_hide_header 'Access-Control-Allow-Origin';

    # Sets the new value
    add_header Access-Control-Allow-Origin https://www.mydomain.com;
  }
}

@yevon
Copy link
Contributor Author

yevon commented Sep 23, 2022

Yes sorry, it indeed worked adding proxy hide headers thanks all! Closing this.

@yevon yevon closed this as completed Sep 23, 2022
@elimisteve
Copy link
Contributor

elimisteve commented Mar 24, 2023

In case it's useful to my fellow Gophers...

How to do the same thing as above, but using Go rather than Nginx as your reverse proxy:

postgrestURL, _ := url.Parse("http://localhost:3000")
postgrestProxy := httputil.NewSingleHostReverseProxy(postgrestURL)
postgrestProxy.ModifyResponse = func(resp *http.Response) error {
        resp.Header.Del("Access-Control-Allow-Origin")  // Delete too-permissive header coming back from PostgREST
        resp.Header.Set("Access-Control-Allow-Origin", "https://www.mydomain.com")
        return nil
}
handlePostgrest := http.StripPrefix("/postgrest", postgrestProxy)

// Using gorilla/mux:
r := mux.NewRouter()
r.PathPrefix("/postgrest").Handler(handlePostgrest)
http.Handle("/", r)

// Or without gorilla/mux:
http.Handle("/postgrest", handlePostgrest)

@steve-chavez
Copy link
Member

steve-chavez commented Sep 25, 2023

Hm, since we do modify CORS (doc) I think making it configurable is reasonable. It should be simple to implement too.

cors-allowed-origins = "domain1, domain2"

By default it's:

cors-allowed-origins = "*"

Alternatively, this should already be possible with pre-request? Edit: even if it's possible, it should be fine to have the ability to configure it globally.

@steve-chavez steve-chavez reopened this Sep 25, 2023
@steve-chavez steve-chavez added difficulty: beginner Pure Haskell task and removed idea Needs of discussion to become an enhancement, not ready for implementation labels Sep 25, 2023
@taimoorzaeem
Copy link
Collaborator

@steve-chavez How should we handle the case when an Origin: domain header is given in the request? Should it override the cors-allowed-origins config?

@laurenceisla
Copy link
Member

@taimoorzaeem According to MDN, you'll need to:

Limiting the possible Access-Control-Allow-Origin values to a set of allowed origins requires code on the server side to check the value of the Origin request header, compare that to a list of allowed origins, and then if the Origin value is in the list, set the Access-Control-Allow-Origin value to the same value as the Origin value.

It only returns the value specified by Origin in the he Access-Control-Allow-Origin header if found. AFAIK Origin doesn't override the config, it just works as a filter for the list in that config.

@steve-chavez
Copy link
Member

@taimoorzaeem Sorry for the late reply here.

So as per my understanding, if domain is not inside cors-allowed-origins - hence not sent in Access-Control-Allow-Origin - the preflight request will fail. Not sure if we need to set a custom error here, the browser itself should err with an appropriate message.

I also recommend checking the MDN docs that Laurence linked.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
difficulty: beginner Pure Haskell task
Development

Successfully merging a pull request may close this issue.

6 participants