swagger-api / swagger-ui

Swagger UI is a collection of HTML, JavaScript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API.
https://swagger.io
Apache License 2.0
26.57k stars 8.96k forks source link

Swagger UI page resources not loading on Safari over http on localhost; page relative links (js, css) assumed to be over https - by Safari Only #7785

Open kleydon opened 2 years ago

kleydon commented 2 years ago

Environment:

Description

When I run swagger UI from an express server, in Safari on a Mac over http on localhost, using

  app.use("/rest-docs", swaggerUi.serve, swaggerUi.setup(openApi.get()))  

the Swagger UI page html loads, but its relatively linked resources (js, css) don't load.

For each linked file, there is an error like the error below, each assuming that the linked resource should be served over https (even though the Swagger UI html is being served over http, as expected):

Failed to load resource: An SSL error has occurred and a secure connection to the server cannot be made. https://localhost:2020/rest-docs/swagger-ui-bundle.js

This problem occurs on Safari, but does not occur on Chrome or FireFox.

Its unclear to me whether this is a Safari issue, a Swagger issue, or something else. (Since v9, Safari handles mixed http / https content differently, which may (?) be related...)

In Safari, I have:

Could Swagger be forcing use of https for relatively-linked resources of the Swagger UI html, served over http for Safari?

tonykaram1993 commented 2 years ago

I am having the same issue, have you solved this in any way?

Its frustrating me to have two browsers open just to access swagger.

kleydon commented 2 years ago

Its frustrating me to have two browsers open just to access swagger. Agreed; haven't found anything yet.

dbarati-bf commented 2 years ago

Facing the same issue. This only occurs when using the default helmet config (app.use(helmet())).

kleydon commented 2 years ago

This only occurs when using the default helmet config (app.use(helmet())).

It also occurs when using non-default helmet configurations. I'm using the configuration below, and the issue still occurs.

  const cspDirectives = helmet.contentSecurityPolicy.getDefaultDirectives()
  // CSP directive overrides
  // Re: graphiql, see:
  //https://github.com/apollographql/apollo-server/issues/4648
  cspDirectives['default-src'] = [ 
    "'self'",
    ...(useGraphiql ? [ "'unsafe-inline'" ] : []),  // <-- For graphiql
  ]
  cspDirectives['script-src'] = [
    "'self'",
    ...((useGraphiql || true) ? [ "'unsafe-inline'" ] : []),  // <-- For graphiql
    ...(useGraphiql ? [ "'unsafe-eval'" ] : []), // <-- For graphiql
  ]
  cspDirectives['frame-ancestors'] = [ 
    "'self'",
    // Required for locally serving admin site (and possibly other sites) via dev server, 
    // while serving (iframed) Prisma Studio via express
    ...(getEnvVar('PLATFORM')==='local' ? [ "localhost:*" ] : [])
  ]    

  //ilog('CSP Directives:', cspDirectives)

  const helmetOptions:HelmetOptions = {
    contentSecurityPolicy: {
      directives: {
        ...cspDirectives,
      }
    }
  }
  if (useGraphiql) {
    helmetOptions.contentSecurityPolicy!
  }

  app.use((req, res, next) =>
    helmet(helmetOptions)(req, res, next)
  )
hstm commented 2 years ago

Same here with @fastify/swagger. Chrome and Firefox work as expected, Safari doesn't. I tried to apply all known workarounds to disable/clear HSTS settings, but without success.

I found out that Safari's behaviour depends on how resource paths are constructed.

Example:

Original code snippet from a generated index.html file with URL http://localhost:3000/documentation/static/index.html:

    <script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>

doesn't work; Safari changes the path to https://localhost:3000/documentation/static/swagger-ui-bundle.js which isn't accessible on localhost. Error msg as described above ("Failed to load resource: An SSL error has occurred and a secure connection to the server cannot be made.")

Manual response override to fully qualified path using Safari dev tools:

    <script src="http://localhost:3000/documentation/static/swagger-ui-bundle.js" charset="UTF-8"> </script>

also doesn't work; Safari again changes the path to https://localhost:3000/documentation/static/swagger-ui-bundle.js which isn't accessible on localhost.

Manual response override using Safari dev tools, this time with partially qualified path:

    <script src="/documentation/static/swagger-ui-bundle.js" charset="UTF-8"> </script>

actually works; after manually overriding all paths in the index.html file I finally got a fully working Swagger UI.

tonykaram1993 commented 2 years ago

Same here with @fastify/swagger. Chrome and Firefox work as expected, Safari doesn't. I tried to apply all known workarounds to disable/clear HSTS settings, but without success.

I found out that Safari's behaviour depends on how resource paths are constructed.

Example:

Original code snippet from a generated index.html file with URL http://localhost:3000/documentation/static/index.html:

    <script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>

doesn't work; Safari changes the path to https://localhost:3000/documentation/static/swagger-ui-bundle.js which isn't accessible on localhost. Error msg as described above ("Failed to load resource: An SSL error has occurred and a secure connection to the server cannot be made.")

Manual response override to fully qualified path using Safari dev tools:

    <script src="http://localhost:3000/documentation/static/swagger-ui-bundle.js" charset="UTF-8"> </script>

also doesn't work; Safari again changes the path to https://localhost:3000/documentation/static/swagger-ui-bundle.js which isn't accessible on localhost.

Manual response override using Safari dev tools, this time with partially qualified path:

    <script src="/documentation/static/swagger-ui-bundle.js" charset="UTF-8"> </script>

actually works; after manually overriding all paths in the index.html file I finally got a fully working Swagger UI.

I don't have an index.html for swagger. This is how we load swagger:

CleanShot 2022-11-03 at 18 38 41@2x

How do I go about doing what you did?

oNddleo commented 1 year ago

can you change staticCSP: false and go to exactly url: http://localhost:3000/documentation it works for me

JarekParal commented 10 months ago

I have the same issue with documentation generated with FastAPI (@tiangolo/fastapi).

Foxy-Loxy commented 4 weeks ago

For anyone who still has this issue and uses Helmet.js: There is closed issue (https://github.com/helmetjs/helmet/issues/429) where in comments one of maintainers describes why this happens specifically with Safari.

TLDR; Remove "upgrade-insecure-requests" from CSP configuration of Helmet:

helmet({
    contentSecurityPolicy: {
        directives: {
            upgradeInsecureRequests: null
        },
    },
});