PostgREST / postgrest

REST API for any Postgres database
https://postgrest.org
MIT License
23.06k stars 1.02k forks source link

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

Closed yevon closed 10 months ago

yevon commented 2 years ago

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 commented 2 years ago

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

https://github.com/PostgREST/postgrest/blob/a41380b96595499e976f160c03d11a8bfec6a303/src/PostgREST/Cors.hs#L19-L42

yevon commented 2 years ago

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 commented 2 years ago

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

yevon commented 2 years ago

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 commented 2 years ago

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 commented 1 year ago

Just to give an example to hide the access-control-allow-origin header using https://github.com/PostgREST/postgrest/issues/2441#issuecomment-1229217627:

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 commented 1 year ago

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

elimisteve commented 1 year ago

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 commented 11 months ago

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.

taimoorzaeem commented 11 months ago

@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 commented 11 months ago

@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 commented 11 months ago

@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.

steve-chavez commented 11 months ago

@taimoorzaeem Also these docs might be helpful: