Swagger-ui: Mixed content issues due to XHR over HTTP made from HTTPS page

Created on 12 Oct 2015  路  42Comments  路  Source: swagger-api/swagger-ui

If the schemes parameter is configured (and not empty) for an API, Swagger UI picks the _first_ [1] [2] scheme value up for API requests.
For example:

{
    "swagger": "2.0",
    "schemes": [
        "http",
        "https"
    ]
}

As a consequence, _all_ requests will be made over HTTP.

This cause "mixed content issues" when Swagger UI is served/hosted via HTTPS and yet makes regular HTTP requests, as explained above.

[1] https://github.com/swagger-api/swagger-js/blob/master/lib/client.js#L274
[2] https://github.com/swagger-api/swagger-js/blob/master/lib/client.js#L290

P3 bug

Most helpful comment

Any progress on this?

All 42 comments

@dalbani I think this is a bug, because there does seem to be a check on window.location (to see if we need to use https)... https://github.com/swagger-api/swagger-js/blob/master/lib/client.js#L272

Do you have a failing case? If you have the time, please feel free to create a Pull Request. Otherwise, we can put this in the backlog (to investigate and fix).

Indeed, it's in swagger-js that lies the problem (as shown in the 2 links I provided in the bug report).
But I wasn't sure what was the most appropriate place for the fix.
I mean, is swagger-js supposed to have to anything to do with browser-related window.location stuff?
Maybe passing some kind of hint (e.g. rather use HTTPS than HTTP) would be more logical?

well... we could put https above http in the spec (hackish :wink:)
Since swagger-js does http requests, it can know about window.location. And since the only problem I can envision is when ...

a browser on HTTPS requesting HTTP.
Would we need to hint which schema to use? Any other use cases?

Since swagger-js does http requests, it can know about window.location.

Well, I couldn't find a single reference to the browser-specific window or document variables in swagger-js source code.
And this is fine with me, because you can't assume that the JS runtime will _always_ be a browser.
Therefore my idea of some kind of hint passed by the caller (Swagger UI).

Yes, we cannot rely on window to be an object since swagger-js is used in node & browser-less environments.

There are two options on this that come to mind.

First, always _prefer_ requests over https. This is probably the easiest to implement and least controversial.

Second, allow swagger-ui to pass a hint as to which to use. _That_ the index.html can use the window object to get the protocol.

So, I suspect that choosing https when both http, https are available is probably the right choice. But you can certainly have a method which requires http even if the top-level allows http, https. That will trigger the same error.

Indeed, preferring HTTPS over HTTP is the simplest solution. But are we sure that HTTPS is supported in all environments where swagger-js is running? I suppose so, I'm kind of thinking out loud :-)

And what about ws vs wss? How do Swagger UI handles WebSocket at the moment by the way?
If an API is defined with "schemes": [ "http", "https", "ws", "wss" ], how should this be globally handled by Swagger UI/JS?

We're deploying java using swagger annotations into Amazon AWS - https is terminated by the AWS load-balancer and the server is running in http. So swagger.json has "schemes" : [ "http" ], even though the browser is in https...

So IMHO the UI should default to whatever scheme it used to get the swagger.json file. This can be passed in as an (optional) parameter to swagger-js.

Well, that would be ignoring the spec, which isn't a good idea. If you're deploying the schemes to something else, consider either leaving it off (it's optional) or setting the scheme in javascript like such:

window.swaggerUi.api.setSchemes(['https'])

Which will override the spec value.

well, I want to use the packaged UI (from https://github.com/smoketurner/dropwizard-swagger in fact) and the simplest java annotations.

I guess I want to force the java annotations to set no scheme at all so the UI is forced to use the one it knows about... But a lot of people are going to be bitten by this.

https://github.com/swagger-api/swagger-js/pull/665 only checks the ui hint if the scheme setting is empty. I guess this is the way it's going to be.

Yes, that's my suggestion, just leave the schemes empty

just leave the schemes empty

I don't understand the logic of the suggestion.
The goal here is be able to combine those 3 aspects:

  1. "schemes": [ "http", "https" ], because that's how the endpoints are accessible
  2. the browser using the most appropriate protocol (e.g. https if present in schemes and used by the main document)
  3. any other consumer of the Swagger definition using the most appropriate protocol

If schemes is left empty, I can't see how those non-browser consumers could figure out which protocol to use.
It's not as if schemes doesn't serve a purpose, right?

Maybe schemes does serve a purpose for some but for me it gets in the way as we're deploying in many different environments: dev, CI, on prem servers, behind a ssl-terminator, etc.

The UI knows what scheme it used to fetch the swagger.json file so, in the absence of any other information, use that as the default.

I do agree that if there is nothing set for schemes, we should use what the browser is using.

Any progress on this?

has there been any progress on this bug?

I think the logic

  1. If the browser's scheme is in schemes, use it
  2. Otherwise, use the first scheme

Makes some sense, and would handle most cases. What are everyone's thoughts?

@wjagodfrey that sounds good.

I think this was fixed in 2.2.0. Do you still see it there?

Good to know. I'm running 2.1.4. Trying 2.2.0 now.

@fehguy That seems to have solved the issue. Thanks for the tip 馃嵑

awesome! Thanks

Checking the window for 'http' or 'https' makes sense, otherwise some form of retry that iterates through the schemes would be an enhancement over selecting only one of them.

Seems to be broken on master (today), since a scheme that has ['https','http'] when loaded in a http://localhost is trying to use the first scheme 'https' instead of the browser scheme 'http'.

Seems broken in 2.2.3 still, same behavior as described by mr. @darrenleeweber

Turns out not to be fixed after all. Apologies for the false positive.

Please test on master, it is not in a release yet, slated for 2.2.4

FYI it seems that got fixed in 2.2.6. I assume this issue can be closed.

Any idea when you expect this to be available on http://petstore.swagger.io/?

the petstore has been updated to 2.2.10

That's strange. Our Swagger spec is served over https and it starts this way:

swagger: '2.0'
info:
  title: Yona app service API
  description: The API of the service backing the Yona app
  version: 1.0.0
schemes:
  - http
  - https
basePath: /
produces:
  - application/json
paths:
  /users/:

Still, all Curl requests use http:

curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' --header 'Yona-Password: abc' -d '{ \ 
   "firstName": "Richard", \ 
   "lastName": "Quin", \ 
   "mobileNumber": "+31612345678", \ 
   "nickname": "RQ" \ 
 }' 'http://beta.prd.yona.nu/users/'

Any idea what's wrong?

You're using the online petstore demo to host your own documentation?

No, to occasionally use it. Normally works like a charm.

@webron why not? Is it unreliable?

Oh, people should use it as much as they want, but we don't guarantee an SLA, and I wouldn't want to give users of a commercial product a link such as https://petstore.swagger.io?url=.... But for general testing? Sure.

That's what we do. Any idea why it doesn't work with https?

Ah just a minute. There was a bug in swagger-js that was just fixed yesterday. Swagger-UI doesn't have the swagger-js-2.1.31 yet, but will today. So @Bert-R it's possible that the calls _will work_ but curl is reported incorrectly. See here for details:

https://github.com/swagger-api/swagger-js/issues/931
https://github.com/swagger-api/swagger-js/issues/903

OK, I'll check back tomorrow. Thanks!

I tried it again and this is the status:

  • GET works. The UI shows that curl uses http, but apparently handles the redirect to https
  • POST does not work.

You can try that here http://petstore.swagger.io/?url=https%3A%2F%2Fbeta.prd.yona.nu%2Fswagger%2Fswagger-spec.yaml#!/Admin/post_admin_requestUserOverwrite

Type anything in the mobile number field and hit Try It Out. That should return you a 400 (assuming you won't guess a valid mobile number :) )

@Bert-R I set the scheme for your api to https in my console and all was fine:

swaggerUi.api.setSchemes(['https'])

If you change your definition from this:

schemes:
  - http
  - https

To this:

schemes:
  - https
  - http

then https will be selected first.

@fehguy I tried that, but that doesn't work for me. Can you have another look?

@fehguy: After I switched the order of the schemes, the problem still exists. Can you please look into this once more?

I'm in the same situation. I tried the recommendation of switching the schemes and it still happens. The only thing that worked for me was to make find and replace in the swagger-ui html code, http://petstore.swagger.io/v2/swagger.json with the location of my swagger.json with HTTPS.

However, this results in an annoying error message in the footer: Can't read from file https://partner.mycompany.com/reg-service/docs/swagger/swagger.json but that file is reachable. In spite of that, this is the lesser of two evils.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

shockey picture shockey  路  3Comments

sgyang picture sgyang  路  4Comments

liuya05 picture liuya05  路  3Comments

easyest picture easyest  路  3Comments

ilnurshax picture ilnurshax  路  3Comments