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

Ability to specify CORS accepted origins #16714

Closed
tylersmalley opened this issue Feb 13, 2018 · 59 comments · Fixed by #84316
Closed

Ability to specify CORS accepted origins #16714

tylersmalley opened this issue Feb 13, 2018 · 59 comments · Fixed by #84316
Assignees
Labels
enhancement New value added to drive a business result Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc

Comments

@tylersmalley
Copy link
Contributor

Currently server.cors accepts a boolean when in production. Setting this to true, uses * for the accepted origins. Users should be able to specify the origins like we do in dev for Karma ['*://localhost:9876']

@tylersmalley tylersmalley added the Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc label Feb 13, 2018
@spalger spalger added the enhancement New value added to drive a business result label Feb 14, 2018
@anton-putau
Copy link

anton-putau commented Feb 14, 2018

This also not works

cors: Joi.when('$dev', {
      is: true,
      then: Joi.boolean().default(true),
      otherwise: Joi.boolean().default(true)
    })

Tested on windows 10 for 5.6

It seems adding header via proxy can be a solution currently

@rnkhouse
Copy link

rnkhouse commented Apr 23, 2019

Any update on this?
I setup kibana config with

server.cors: true
server.cors.origin: ["*"]

But, still getting cross-origin error.

@katzelad
Copy link

katzelad commented May 21, 2019

Also, allowing customization of some other CORS properties would be very helpful.
In order to allow automatic login from an external domain I had to modify http_tools.js as follows:
cors: { additionalHeaders: ['kbn-version','cookie'], origin: ['*'], credentials: true }
It would be nice to be able to configure this from kibana.yml.

@epixa epixa added Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc and removed Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc labels May 22, 2019
@elasticmachine
Copy link
Contributor

Pinging @elastic/kibana-platform

@katzelad
Copy link

katzelad commented May 27, 2019

@tylersmalley Will you consider accepting a PR?
CORS options would be set by kibana.yml parameters, for example:
server.cors.origin: ["*"]
server.cors.additionalHeaders: ["kbn-version", "cookie"]
server.cors.credentials: true

@afdezl
Copy link

afdezl commented Dec 16, 2019

Hi, any updates on this? Would be extremely useful. Thanks.

@Joao-pina-fernandes
Copy link

Hi,

I have this configuration on my kibana-yml,

server.cors: true
server.cors.origin: ["*"]

And when requesting this endpoint, https://localhost:5601/api/saved_objects/_find?type=dashboard, the response does not add the Access-Control-Allow-Origin Header.

Is cors enabled for the kibana Rest API?

Thanks

@joshdover
Copy link
Contributor

I apologize, it appears this feature was documented in #47701 when it should not have been. It is currently only available in dev mode which cannot be enabled in production builds.

We have not prioritized add this feature yet. If you could explain your usecase for CORS headers, that would help us prioritize accordingly. Thank you!

@mishat-realityi
Copy link

@joshdover The usecase for CORS headers would be using an iFrame.

@joshdover
Copy link
Contributor

Hi @mishat-realityi, could you go in more detail about what you are trying to accomplish? What would help me understand is the user experience you are trying to create, beyond just the technical details.

@mishat-realityi
Copy link

mishat-realityi commented Mar 11, 2020

Sure @joshdover ,
Here is the problem and it easy to reproduce.

  1. Build elastic stack within docker.
  2. Enable security settings in elasticsearch.yml:
    • xpack.security.enabled=true
    • xpack.security.transport.ssl.enabled=true
    • xpack.security.transport.ssl.keystore.type=PKCS12
    • xpack.security.transport.ssl.verification_mode=certificate
    • xpack.security.transport.ssl.keystore.path=elastic-certificates.p12
    • xpack.security.transport.ssl.truststore.path=elastic-certificates.p12
    • xpack.security.transport.ssl.truststore.type=PKCS12
  3. Create dashboard share as iFrame and make index.html with it.
  4. When you launch index.html no matter which user you use you will get CORS error in your console such as:

Blocked a frame with origin "http://localhost:5601" from accessing a frame with origin "null"

So as results you wouldn't be able to bypass authentication part in iframe until you enable in kibana.yml
server.cors: true
server.cors.origin: ["http://localhost:5601"]

Screen Shot 2020-03-11 at 5 50 32 PM

This makes iframe with authentication practically unusable. I think it should be documented.

I hope it makes sense.

@joshdover
Copy link
Contributor

I don't believe the problem you are encountering is a CORS issue. iframes must be hosted on the same protocol, which means that you need to access the index.html file via a HTTP server rather than via a file://... URL in your browser.

You'll need to start an HTTP server that hosts this file. If you have Node.js installed, I recommend trying out the http-server package for a dead-simple file hosting server: npx http-server path/to/directory

@rafaelaca
Copy link

Hi @joshdover
Since you asked about use cases, here it goes:

I believe that the Dashboard "share" idea is to use the Dashboard into other web applications, right?

The problem is that if my webapplicatoin user is not logged in Kibana, all the embed dashboard will show will be the login page..

How can I accomplish this? Embed a dashboard into my webpage and not requiring the user to be logged in.

One solution that I see people trying is, to make an AJAX request to /api/security/v1/login passing the credentials, so the browser could set the proper cookie, and then redirect to the dashboard URL.

Unfortunately this approach doesn't work, and I believe it is because this CORS issue.

If this is not the problem, how can I embed a Dashboard into my webapp without requiring the user to login.

Here are some threads about this issue:
https://discuss.elastic.co/t/iframe-embed-cross-origin-security-exception/101035
https://discuss.elastic.co/t/kibana-skip-login-page/167323/2

Thanks in advance!

Hi @mishat-realityi, could you go in more detail about what you are trying to accomplish? What would help me understand is the user experience you are trying to create, beyond just the technical details.

@gnumoksha
Copy link

I have the exact same issue as @rafaelaca

@rafaelzurlo-zz
Copy link

I also have the same problem as @rafaelaca and @gnumoksha.

@glaucomorandini
Copy link

I also have the same problem. @joshdover do you have any solution or something can I do to solve this?

@germanoclodi
Copy link

@joshdover Any development in this issue? I am having the exactly same problem as @rafaelaca

@snava10
Copy link

snava10 commented May 26, 2020

@joshdover I'm experiencing the same problem, this seems to me like a simple enough change and it would be greatly appreciated.

@metalice
Copy link

metalice commented Jul 1, 2020

@joshdover exactly same thing for us. please address the cors issue

@pgayvallet
Copy link
Contributor

pgayvallet commented Sep 8, 2020

I think we should continue to disallow these headers, and instead require administrators to whitelist via server.xsrf.whitelist if that's required

I think that would not be enough for actual cors requests, does it? The Access-Control-Allow-Headers header would still need to be properly populated, or am I missing something?

EDIT: nevermind, just looked as how the xsrf interceptor was working. However, I'm not sure this is a viable option for users that want to allow access to the whole backend (but I lack actual use cases from users to actually be sure this is something that may have an actual usage)

@legrego
Copy link
Member

legrego commented Sep 8, 2020

However, I'm not sure this is a viable option for users that want to allow access to the whole backend

IMO if they truly want to allow access to the entire backend, then they can be explicit about that via the existing server.xsrf.disableProtection: true configuration option

@VimCommando
Copy link

+1 on renaming server.cors to server.cors.enabled. The way it stands right now having servers.cors: ture and servers.cors.origin: [*] defined can break configurations depending on the version. I saw a Kibana upgrade from v7.8 to v7.9.1 start throwing this error:

kibana[4655]: FATAL Error: [config validation of [server].cors]: expected value of type [boolean] but got [Object]

Which makes sense, and it was probably not the correct configuration to start with, but it passed validation in v7.8.

@mshustov
Copy link
Contributor

mshustov commented Nov 23, 2020

However, I think it'd be worthwhile to expose an option to configure the credentials option. Users can choose to expose certain routes (such as the status page) as unauthenticated endpoints. They might wish to use this in a cross-origin fashion, while still preventing cross-origin access to authenticated endpoints.

My +1 here. Note that credentials: true cannot be used with origin: '*'`. From https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin:

For requests without credentials, the literal value "*" can be specified, as a wildcard; the value tells browsers to allow requesting code from any origin to access the resource. Attempting to use the wildcard with credentials will result in an error.

As a result, config is going to look like this:

cors: schema.object({
  enabled: schema.boolean({ defaultValue: false }),
  credentials: schema.boolean({ defaultValue: false }),
  origin: schema.oneOf([
    schema.literal('*'),
    schema.arrayOf(hostURISchema, { minSize: 1 }
  ],
  {
      defaultValue: '*',
  }),
},{
  validate(value) {
    if (value.credentials === true && value.origin === '*') {
      return 'Cannot specify wildcard origin "*" with "credentials: true". Please provide a list of allowed origins.';
    }
  },
}),

IMO if they truly want to allow access to the entire backend, then they can be explicit about that via the existing server.xsrf.disableProtection: true configuration option

  1. Then we need to make CORS setup documentation as a part of this issue.
  2. It contradicts our general recommendations for API usage https://www.elastic.co/guide/en/kibana/master/using-api.html#api-request-headers Also it disabled Kibana version check implemented via headers
  3. Worth noting server.xsrf.whitelist is deprecated
    'It will be removed in 8.0 release. Instead, supply the "kbn-xsrf" header.'

Also, we need to provide recommendations on sameSite cookie configuration. Users will have to disable this mechanism with:

xpack.security.sameSiteCookies: None
xpack.security.secureCookies: true

which will require Secure context to be always on.
@legrego waiting for your feedback

@legrego
Copy link
Member

legrego commented Nov 30, 2020

@restrry sorry for the delay, catching up from my vacation:

Then we need to make CORS setup documentation as a part of this issue.

I think CORS setups docs would be good to have regardless of the approach we take here.

It contradicts our general recommendations for API usage elastic.co/guide/en/kibana/master/using-api.html#api-request-headers

I think I'm missing something here. The general recommendation is to provide the kbn-xsrf header, unless you've explicitly disabled protections, either via the server.xsrf.whitelist or server.xsrf.disableProtections settings. Where is the contradiction?

Worth noting server.xsrf.whitelist is deprecated

Thanks, I wasn't aware of this. I knew we deprecated using this setting for our own IdP routes, but I didn't know that we're taking this away from users altogether. What is the motivation for removing this setting?

Also, we need to provide recommendations on sameSite cookie configuration. Users will have to disable this mechanism with:

xpack.security.sameSiteCookies: None
xpack.security.secureCookies: true

Yep, we should make sure to include these recommendations as part of our docs changes.

which will require Secure context to be always on.

If security is disabled, then cookies/credentials shouldn't play a role here, right? There shouldn't be a need to provide the server with credentials if security is disabled.

@mshustov
Copy link
Contributor

mshustov commented Dec 1, 2020

The general recommendation is to provide the kbn-xsrf header, unless you've explicitly disabled protections, either via the server.xsrf.whitelist or server.xsrf.disableProtections settings. Where is the contradiction?

Ok, my bad. I thought that you are against advising 3rd party services providing the kbn-xsrf header.

I knew we deprecated using this setting for our own IdP routes, but I didn't know that we're taking this away from users altogether. What is the motivation for removing this setting?

It's been discussed at #53823 (comment). I'm fine to remove the deprecation warning if you say so.

If security is disabled, then cookies/credentials shouldn't play a role here, right? There shouldn't be a need to provide the server with credentials if security is disabled.

Sorry for being unclear here. Secure context === requires HTTPS. from https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite: Cookies with SameSite=None must now also specify the Secure attribute (they require a secure context/HTTPS).

I think CORS setups docs would be good to have regardless of the approach we take here.

👍 Should I create an issue for the Core or Docs team? @joshdover


@legrego @elastic/kibana-core Can you see any reasons not to provide cors support on Cloud?

@legrego
Copy link
Member

legrego commented Dec 1, 2020

I knew we deprecated using this setting for our own IdP routes, but I didn't know that we're taking this away from users altogether. What is the motivation for removing this setting?

It's been discussed at #53823 (comment). I'm fine to remove the deprecation warning if you say so.

I think this is still a worthwhile configuration option for the more esoteric use cases. We already give admins a way to turn off CSRF protections altogether, so allowing them to turn off protections for a subset of URLs seems like a very reasonable thing to do. @azasypkin any objections to removing the deprecation warning for server.xsrf.whitelist?

Actually, perhaps we should keep the deprecation, but instead of saying that this will be removed, we can instead deprecate the current setting in favor of server.xsrf.allowList, or a similarly neutral name?

Sorry for being unclear here. Secure context === requires HTTPS. from developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite: Cookies with SameSite=None must now also specify the Secure attribute (they require a secure context/HTTPS).

Ah sorry for the confusion. I think there's two parts to this:

  1. Not allowing SameSite=None for insecure connections. We protect against this already.
  2. Enforcing xpack.security.secureCookies: true when SameSite=None. We warn against this today, but perhaps we should take a stricter approach and abort startup in 8.0?

Validations aside, I think your real question was around user guidance and docs. We can make sure to address this as part of the docs writeup for this feature.

Can you see any reasons not to provide cors support on Cloud?

I don't see a reason why we can't expose these settings on Cloud. We'll want to make sure it's compatible (i.e., that the proxies won't interfere), but I don't have any concerns with allowing this. I think it would be frustrating for users if we didn't have support on Cloud for this.

@azasypkin
Copy link
Member

@azasypkin any objections to removing the deprecation warning for server.xsrf.whitelist?

No objections from my side if there is a need for it. I think that was me who suggested to completely remove it since we added it initially just for the SAML use case and I've never heard of any other usage for it since then.

Actually, perhaps we should keep the deprecation, but instead of saying that this will be removed, we can instead deprecate the current setting in favor of server.xsrf.allowList, or a similarly neutral name?

++

@kobelb
Copy link
Contributor

kobelb commented Dec 4, 2020

If we allow kbn-version or kbn-xsrf to be provided, then we are bypassing Kibana's CSRF protections for the configured origins. I think we should continue to disallow these headers, and instead require administrators to whitelist via server.xsrf.whitelist if that's required.

I respectfully disagree. By requiring that a custom header is specified, it requires that the browser initiate a CORS pre-flight request, that includes the origin and allows us to relax the same-origin restrictions for trusted domains. Adding an endpoint to the server.xsrf.allowlist will allow ANY origin to access this endpoint. What's the point in having users configure server.cors.origin then? However, I can see an argument being made for us to add a server.cors.allowlist, so that we can only allow HTTP requests from certain origins to certain endpoints.

I don't believe that these headers are needed for the traditional "iframe embed" use case.

FWIW, I don't think we should be incentivizing the use of this approach to authenticate to Kibana in an iframe. We have first-class support for anonymous access now per #79985 that allows us to authenticate as a static-user. If we want a dynamic user, we should be using one of our realms that supports single-sign on.

@legrego
Copy link
Member

legrego commented Dec 4, 2020

I respectfully disagree. By requiring that a custom header is specified, it requires that the browser initiate a CORS pre-flight request, that includes the origin and allows us to relax the same-origin restrictions for trusted domains. Adding an endpoint to the server.xsrf.allowlist will allow ANY origin to access this endpoint. What's the point in having users configure server.cors.origin then? However, I can see an argument being made for us to add a server.cors.allowlist, so that we can only allow HTTP requests from certain origins to certain endpoints.

I'm likely misunderstanding something here, I apologize. It's my understanding that server.xsrf.allowlist doesn't impact our CORS implementation. In order for a browser to successfully make a cross-origin call, it has to satisfy the pre-flight request, and if the origin isn't configured within server.cors.origin, then the pre-flight will fail, and the browser will refuse to make the request.

If the pre-flight request is satisfied, then the browser will permit the cross-origin request, and only at that point will our xsrf protections come into play.

You're right, sorry for the confusion. Without specifying the additionalHeaders to allow kbn-xsrf, the CORS requests will never be allowed to complete.

However, I can see an argument being made for us to add a server.cors.allowlist, so that we can only allow HTTP requests from certain origins to certain endpoints.

++ I think this is would give us the flexibility that I was envisioning

@legrego
Copy link
Member

legrego commented Dec 4, 2020

@jportner would you mind weighing in here to make sure @kobelb and I aren't overlooking anything? To recap, we are proposing to do what Pierre originally suggested by allowing cross-origin requests to specify the kbn-xsrf header. This will allow browsers to make cross-origin POST/PUT/DELETE requests to Kibana when properly configured with CORS for the intended origin.

Additionally, we are proposing to add a server.cors.allowlist, to allow administrators to optionally specify a subset of endpoints that should be accessible in a cross-origin context.

I originally had concerns that allowing kbn-xsrf to be specified would bypass our XSRF protections, but this only comes into play when an administrator explicitly enables CORS, which is disabled by default. But disallowing the kbn-xsrf header prevents essentially non-GET requests from executing in a cross origin fashion, because these requests won't be allowed to present this header

@jportner
Copy link
Contributor

jportner commented Dec 4, 2020

@jportner would you mind weighing in here

I think what you recapped makes sense.

Our XSRF defense relies on same origin policy, so IMO it should be aligned/relaxed with configurable CORS settings.

At this point the only function of the kbn-xsrf header defense is to make sure that HTML injection exploits on trusted 3rd-party origins cannot be used for XSRF attacks against Kibana; instead, an attacker must achieve XSS on a trusted 3rd-party origin to then attempt XSRF against Kibana, which is a higher bar to clear.

Just to reiterate what @restrry said:

Note that credentials: true cannot be used with origin: '*'

We need to make this clear to admins: when they configure server.cors.enabled that they must also configure specific origins in server.cors.origin to allow cross-site requests with credentials. We do have at least one valid use case where credentials are not needed (anonymous access), so we shouldn't throw an error if this configuration is used. I'm a bit concerned that users will overlook console warnings though. Not sure what the answer is here; perhaps we should force users to specify server.cors.origin instead of defaulting to ['*']?

@kobelb
Copy link
Contributor

kobelb commented Dec 4, 2020

Not sure what the answer is here; perhaps we should force users to specify server.cors.origin instead of defaulting to ['*']?

👍 @restrry's implementation has a slight permutation on this:

server.cors.origin: List of origins permitted to access resources. You must specify explicit hostnames and not use * for server.cors.origin when server.cors.credentials: true. Default: "*"

@jportner
Copy link
Contributor

jportner commented Dec 4, 2020

restrry's implementation has a slight permutation on this:

🙌 🙌 🙌

@legrego
Copy link
Member

legrego commented Dec 4, 2020

👍 thanks, Joe!

@azasypkin
Copy link
Member

We do have at least one valid use case where credentials are not needed (anonymous access), so we shouldn't throw an error if this configuration is used.

FWIW, if you meant anonymous authentication provider and not reverse-proxy based "anonymous" access then we do require credentials (session cookie) as well.

@mshustov
Copy link
Contributor

mshustov commented Dec 7, 2020

We do have at least one valid use case where credentials are not needed (anonymous access), so we shouldn't throw an error if this configuration is used.

API endpoints with disabled auth? api/status, for example.

I'm a bit concerned that users will overlook console warnings though.

Kibana refuses to start with an invalid config.

perhaps we should force users to specify server.cors.origin instead of defaulting to ['*']?

Sure, we can change defaults to allow credentials but require list of allowed origins:

      cors: schema.object(
        {
          enabled: schema.boolean({ defaultValue: false }),
          credentials: schema.boolean({ defaultValue: true }),
          origin: schema.oneOf([schema.literal('*'), schema.arrayOf(hostURISchema)], {
            defaultValue: [],
          }),
        },
        {
          validate(value) {
            if (value.credentials && value.origin === '*') {
              return 'Cannot specify wildcard origin "*" with "credentials: true". Please provide a list of allowed origins.';
            }
            if (value.origin.length === 0) {
              return '"origin" must contain at least one valid URL';
            }
          },
        }
      ),

It will throw if server.cors.enabled: true but server.cors.origin is not defined explicitly.
If a user set server.cors.credentials: false, they will be able to set server.cors.origin: *. WDYT @jportner ?

At this point the only function of the kbn-xsrf header defense is to make sure that HTML injection exploits on trusted 3rd-party origins cannot be used for XSRF attacks against Kibana; instead, an attacker must achieve XSS on a trusted 3rd-party origin to then attempt XSRF against Kibana, which is a higher bar to clear.

So we should list CSRF protection headers kbn-version and kbn-xsrf in Access-Control-Request-Headers?

@jportner
Copy link
Contributor

jportner commented Dec 8, 2020

API endpoints with disabled auth? api/status, for example.

I was originally thinking of the anonymous auth provider, but as @azasypkin pointed out, that requires a cookie. But yes this is another use case!

Kibana refuses to start with an invalid config.

Yes, I was replying with regards to Pierre's proposal above which did not include validation, sorry I missed your newer comment and subsequent PR where you included some validation!

Sure, we can change defaults to allow credentials but require list of allowed origins:

...

It will throw if server.cors.enabled: true but server.cors.origin is not defined explicitly.
If a user set server.cors.credentials: false, they will be able to set server.cors.origin: *. WDYT @jportner ?

I like it!

Edit: I missed the change to default to credentials: true, do we need to make that change? My preference would be to default to the most secure configuration.

So we should list CSRF protection headers kbn-version and kbn-xsrf in Access-Control-Request-Headers?

Access-Control-Request-Headers originate from the browser, I think you meant Access-Control-Allow-Headers (e.g. by passing the additionalHeaders parameter to Hapi)? In that case, yes we should add kbn-xsrf to that, but I don't think we should add kbn-version. The latter is not documented for third-party use and we want to discourage its proliferation.

@mshustov
Copy link
Contributor

done in #84316

@gaetano603
Copy link

gaetano603 commented Feb 1, 2021

I modified the http_tools.js file to enable CORS like this.
cors: { additionalHeaders: ['kbn-version','kbn-xsrf','cookie'], origin: ['*'], credentials: true },
instead of cors: config.cors.
My goal is to skip login page sending an HTTP POST request from an Angular script.
The problem is that I am redirected to the login page and I cannot bypass it
Do I need to add anything else to enable CORS?
I am in version 7.6.2

@mshustov
Copy link
Contributor

mshustov commented Feb 1, 2021

Do I need to add anything else to enable CORS?

Why do you think it doesn't work? Do you see any CORS-related errors in the console?

@gaetano603
Copy link

No there are no errors on the console because the http call returns status 204.
But the problem is that the cookie is not set.
Once the cookie is set, I shouldn't have any more problems authenticating by bypassing the login page.

@fatehMohamed14
Copy link

@gaetano603 do you know where is http_tools located , can i created a volume for that change in case of docker

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New value added to drive a business result Team:Core Core services & architecture: plugins, logging, config, saved objects, http, ES client, i18n, etc
Projects
None yet
Development

Successfully merging a pull request may close this issue.